antigravity-rtl-patcher 3.0.0 → 3.0.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/README.md CHANGED
@@ -1,233 +1,65 @@
1
1
  # Antigravity RTL Patcher
2
2
 
3
- Advanced RTL and Persian/Arabic typography support for the [Antigravity](https://antigravity.dev) desktop app. Patches the Electron runtime to detect right-to-left text and apply proper styling with a rich, customizable UI.
3
+ RTL and Persian/Arabic text support for [Antigravity](https://antigravity.dev) desktop app.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/antigravity-rtl-patcher)](https://www.npmjs.com/package/antigravity-rtl-patcher)
6
6
  [![npm downloads](https://img.shields.io/npm/dt/antigravity-rtl-patcher)](https://www.npmjs.com/package/antigravity-rtl-patcher)
7
- [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
8
7
 
9
- ---
10
-
11
- ## ✨ What's New in v3.0
12
-
13
- - 🎨 **Advanced UI Panel** - Hover widget with comprehensive customization options
14
- - 🔤 **Custom Font Support** - Set separate fonts for Persian, English, and code
15
- - 📏 **Typography Controls** - Adjust line height and font size in real-time
16
- - 💾 **Persistent Config** - Settings saved to `~/.antigravity-rtl-v3.json`
17
- - ⚡ **Keyboard Shortcuts** - `Alt + R` to toggle RTL, `Shift + 2` for @ symbol
18
- - 🔧 **Force RTL Mode** - Override auto-detection for consistent RTL layout
19
- - 🎯 **Enhanced Detection** - Smarter RTL text recognition algorithm
20
- - 🚀 **DevTools Enabled** - Built-in developer tools for debugging
21
-
22
- ---
23
-
24
- ## ⚡ Quick Install
25
-
26
- Always use `@latest` to ensure you get the newest version:
8
+ ## Install
27
9
 
28
10
  ```bash
29
11
  npx antigravity-rtl-patcher@latest patch
30
12
  ```
31
13
 
32
- If Antigravity is installed in a system directory, use `sudo`:
14
+ Use `sudo` if Antigravity is in a system directory:
33
15
 
34
16
  ```bash
35
17
  sudo npx antigravity-rtl-patcher@latest patch
36
18
  ```
37
19
 
38
- Restart Antigravity after patching to see the RTL widget appear in the bottom-right corner!
20
+ Restart Antigravity after patching.
39
21
 
40
- ---
22
+ ## Usage
41
23
 
42
- ## 🔄 Update to Latest Version
24
+ After patching, a toggle button appears in the bottom-right corner. Click it to enable/disable RTL support.
43
25
 
44
- To ensure you're always using the latest version:
26
+ Keyboard shortcut: `Alt + R`
45
27
 
46
- ```bash
47
- npx antigravity-rtl-patcher@latest patch
48
- ```
49
-
50
- Or check for updates manually:
51
-
52
- ```bash
53
- npx antigravity-rtl-patcher@latest update
54
- ```
55
-
56
- The patcher will automatically notify you when a new version is available.
57
-
58
- ---
59
-
60
- ## 🎨 Features
61
-
62
- ### Smart RTL Detection
63
- - Automatically detects Persian, Arabic, and Hebrew text
64
- - Applies proper text direction without breaking layout
65
- - Preserves LTR for code blocks and English text
66
-
67
- ### Rich UI Panel
68
- Hover over the globe icon in the bottom-right corner to access:
69
-
70
- - **RTL Toggle** - Enable/disable RTL support on the fly
71
- - **Force RTL Mode** - Force RTL layout even when text starts with English
72
- - **Custom Fonts**:
73
- - Persian/Arabic font (fallback: Vazirmatn)
74
- - English font (fallback: system font)
75
- - Code font (fallback: monospace)
76
- - **Typography Controls**:
77
- - Line height slider (1.2 - 2.5)
78
- - Font size slider (11px - 22px)
79
- - **@ Sign Fix** - Type `@` with `Shift+2` on Persian keyboard
80
- - **Keyboard Shortcut** - `Alt + R` to toggle RTL
81
-
82
- ### Persistent Configuration
83
- All your settings are automatically saved to `~/.antigravity-rtl-v3.json` and restored on restart.
84
-
85
- ---
86
-
87
- ## 🗑️ Uninstall
88
-
89
- Remove the RTL patch and restore original Antigravity:
28
+ ## Uninstall
90
29
 
91
30
  ```bash
92
31
  npx antigravity-rtl-patcher restore
93
32
  ```
94
33
 
95
- Or with sudo if needed:
96
-
97
- ```bash
98
- sudo npx antigravity-rtl-patcher restore
99
- ```
100
-
101
- ---
102
-
103
- ## 📋 Commands
34
+ ## Commands
104
35
 
105
36
  | Command | Description |
106
37
  |---------|-------------|
107
- | `agy-rtl patch` | Apply RTL patch with advanced UI |
108
- | `agy-rtl restore` | Remove patch and restore original |
109
- | `agy-rtl status` | Show current patch status |
110
- | `agy-rtl update` | Check for patcher updates |
111
- | `agy-rtl patch --path /custom/path` | Patch custom installation |
112
- | `agy-rtl patch --skip-update-check` | Skip update check during patching |
113
-
114
- ---
115
-
116
- ## 🔧 How It Works
38
+ | `agy-rtl patch` | Apply RTL patch |
39
+ | `agy-rtl restore` | Remove patch |
40
+ | `agy-rtl status` | Show patch status |
41
+ | `agy-rtl update` | Check for updates |
117
42
 
118
- Antigravity is built on Electron. The patcher:
43
+ ## How It Works
119
44
 
120
- 1. **Extracts** `app.asar` (the packaged application)
121
- 2. **Locates** `dist/utils.js` (window creation module)
122
- 3. **Injects** RTL engine at the window lifecycle hook
123
- 4. **Repacks** the modified application
45
+ The patcher modifies Antigravity's `app.asar` to inject RTL detection logic. It automatically detects Persian, Arabic, and Hebrew text and applies proper text direction.
124
46
 
125
- The RTL engine uses:
126
- - `MutationObserver` for real-time DOM monitoring
127
- - Unicode range analysis for RTL detection
128
- - Dynamic CSS generation for typography control
129
- - Electron IPC for config persistence
47
+ ## After Antigravity Updates
130
48
 
131
- After patching, a hover-activated widget appears in the bottom-right corner with all customization options.
132
-
133
- ---
134
-
135
- ## 🔄 After Antigravity Updates
136
-
137
- Antigravity updates may overwrite the patch. Simply run:
49
+ Run the patch command again after updating Antigravity:
138
50
 
139
51
  ```bash
140
52
  npx antigravity-rtl-patcher@latest patch
141
53
  ```
142
54
 
143
- **Pro tip:** Always use `@latest` to ensure you're using the newest patcher version.
144
-
145
- ---
146
-
147
- ## 💻 Supported Platforms
148
-
149
- | Platform | Typical Install Locations |
150
- |----------|---------------------------|
151
- | **Linux** | `/opt/Antigravity`<br>`~/Downloads/Antigravity-x64`<br>`~/.local/share/antigravity` |
152
- | **macOS** | `/Applications/Antigravity.app`<br>`~/Applications/Antigravity.app` |
153
- | **Windows** | `%LOCALAPPDATA%\Programs\Antigravity`<br>`%PROGRAMFILES%\Antigravity` |
154
-
155
- Custom paths are supported via `--path` option.
156
-
157
- ---
158
-
159
- ## ⌨️ Keyboard Shortcuts
160
-
161
- - **Alt + R** - Toggle RTL support on/off
162
- - **Shift + 2** - Type `@` symbol (when @ fix is enabled)
163
-
164
- ---
165
-
166
- ## 🎯 Configuration File
167
-
168
- Settings are stored in `~/.antigravity-rtl-v3.json`:
169
-
170
- ```json
171
- {
172
- "faFont": "",
173
- "enFont": "",
174
- "codeFont": "",
175
- "lineHeight": "1.6",
176
- "fontSize": "16",
177
- "rtlEnabled": true,
178
- "forceRTL": false,
179
- "fixAtSign": true
180
- }
181
- ```
182
-
183
- You can manually edit this file or use the UI panel.
184
-
185
- ---
186
-
187
- ## 🐛 Troubleshooting
188
-
189
- ### Patch not working?
190
- 1. Make sure you restarted Antigravity after patching
191
- 2. Check patch status: `agy-rtl status`
192
- 3. Try restoring and re-patching:
193
- ```bash
194
- npx antigravity-rtl-patcher restore
195
- npx antigravity-rtl-patcher@latest patch
196
- ```
197
-
198
- ### Widget not appearing?
199
- 1. Open DevTools (now enabled by default)
200
- 2. Check console for any RTL engine errors
201
- 3. Make sure RTL is enabled in the widget
202
-
203
- ### Permission denied?
204
- - **Linux/macOS**: Use `sudo` for system-wide installations
205
- - **Windows**: Run terminal as Administrator
206
-
207
- ---
208
-
209
- ## 🤝 Contributing
210
-
211
- Issues and pull requests are welcome at [github.com/VaFa1726/antigravity-rtl-patcher](https://github.com/VaFa1726/antigravity-rtl-patcher).
212
-
213
- ---
214
-
215
- ## 📄 License
216
-
217
- MIT © VaFa1726
218
-
219
- ---
220
-
221
- ## 🙏 Credits
55
+ ## Supported Platforms
222
56
 
223
- - Built with ❤️ for the Persian/Arabic developer community
224
- - Vazirmatn font by [Saber Rastikerdar](https://github.com/rastikerdar/vazirmatn)
225
- - Powered by Electron ASAR tools
57
+ - Linux: `/opt/Antigravity`, `~/Downloads/Antigravity-x64`
58
+ - macOS: `/Applications/Antigravity.app`
59
+ - Windows: `%LOCALAPPDATA%\Programs\Antigravity`
226
60
 
227
- ---
61
+ Use `--path` option for custom locations.
228
62
 
229
- ## 🔗 Links
63
+ ## License
230
64
 
231
- - [GitHub Repository](https://github.com/VaFa1726/antigravity-rtl-patcher)
232
- - [NPM Package](https://www.npmjs.com/package/antigravity-rtl-patcher)
233
- - [Report Issues](https://github.com/VaFa1726/antigravity-rtl-patcher/issues)
65
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antigravity-rtl-patcher",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "Advanced RTL and Persian/Arabic typography patcher for Antigravity with customizable UI",
5
5
  "main": "src/patcher.js",
6
6
  "bin": {
@@ -1,19 +1,5 @@
1
- /* ═══════════════════════════════════════════════════════════════
2
- * ANTIGRAVITY RTL PATCH v3.0
3
- * Advanced RTL & Typography Control for Antigravity
4
- *
5
- * This code is injected into dist/utils.js at the window creation
6
- * hook point to enable comprehensive RTL support with a rich UI.
7
- * ═══════════════════════════════════════════════════════════════ */
8
-
9
- // ─────────────────────────────────────────────────────────────────
10
- // PATCH MARKER: DO NOT REMOVE
11
- // ─────────────────────────────────────────────────────────────────
12
1
  /* ANTIGRAVITY_RTL_PATCH_v3 */
13
2
 
14
- // ─────────────────────────────────────────────────────────────────
15
- // Hook into console-message for config persistence
16
- // ─────────────────────────────────────────────────────────────────
17
3
  win.webContents.on('console-message', (event, ...args) => {
18
4
  let message = '';
19
5
  if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
@@ -25,659 +11,181 @@ win.webContents.on('console-message', (event, ...args) => {
25
11
  if (typeof message === 'string' && message.startsWith('RTL_CONFIG_SAVE:')) {
26
12
  try {
27
13
  const configData = message.substring(16);
28
- const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl-v3.json');
14
+ const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
29
15
  require('fs').writeFileSync(configPath, configData, 'utf8');
30
16
  } catch (err) {
31
- console.error('[RTL] Failed to save config:', err);
17
+ console.error('[RTL] Config save failed:', err);
32
18
  }
33
19
  }
34
20
  });
35
21
 
36
- // ─────────────────────────────────────────────────────────────────
37
- // Original loadURL call - DO NOT MODIFY THIS LINE
38
- // ─────────────────────────────────────────────────────────────────
39
22
  void win.loadURL(url);
40
23
 
41
- // ─────────────────────────────────────────────────────────────────
42
- // RTL Engine Injection on DOM Ready
43
- // ─────────────────────────────────────────────────────────────────
44
24
  win.webContents.on('dom-ready', () => {
45
25
  try {
46
- // Load Vazirmatn font
47
- const fontPath = require('path').join(__dirname, 'Vazirmatn-Variable.woff2');
48
- const fontBase64 = require('fs').readFileSync(fontPath).toString('base64');
49
-
50
- // Load persisted configuration
51
- const defaultConfig = {
52
- faFont: '',
53
- enFont: '',
54
- codeFont: '',
55
- lineHeight: '1.6',
56
- fontSize: '16',
57
- rtlEnabled: true,
58
- forceRTL: false,
59
- fixAtSign: true
60
- };
61
-
62
- let userConfig = { ...defaultConfig };
26
+ let rtlConfig = { enabled: true };
63
27
  try {
64
- const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl-v3.json');
28
+ const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
65
29
  if (require('fs').existsSync(configPath)) {
66
- const loadedConfig = JSON.parse(require('fs').readFileSync(configPath, 'utf8'));
67
- userConfig = { ...defaultConfig, ...loadedConfig };
30
+ const cfg = JSON.parse(require('fs').readFileSync(configPath, 'utf8'));
31
+ rtlConfig = { ...rtlConfig, ...cfg };
68
32
  }
69
- } catch (err) {
70
- console.warn('[RTL] Could not load config, using defaults:', err);
71
- }
33
+ } catch (err) {}
72
34
 
73
- // ═══════════════════════════════════════════════════════════
74
- // INJECT THE COMPLETE RTL ENGINE INTO RENDERER
75
- // ═══════════════════════════════════════════════════════════
76
35
  win.webContents.executeJavaScript(`
77
- (function initAntigravityRTL() {
78
- 'use strict';
79
-
80
- // Prevent double initialization
81
- if (window.__ANTIGRAVITY_RTL_LOADED__) return;
82
- window.__ANTIGRAVITY_RTL_LOADED__ = true;
83
-
84
- console.log('[RTL Engine] Initializing v3.0...');
85
-
86
- // ═══════════════════════════════════════════════════
87
- // Configuration & State
88
- // ═══════════════════════════════════════════════════
89
- const FONT_BASE64 = '${fontBase64}';
90
- const CONFIG = ${JSON.stringify(userConfig)};
36
+ (function initRTL() {
37
+ if (window.__RTL_LOADED__) return;
38
+ window.__RTL_LOADED__ = true;
91
39
 
92
- let rtlEnabled = CONFIG.rtlEnabled;
93
- let forceRTL = CONFIG.forceRTL;
94
- let fixAtSign = CONFIG.fixAtSign;
40
+ let rtlEnabled = ${rtlConfig.enabled};
95
41
 
96
- // ═══════════════════════════════════════════════════
97
- // Utility Functions
98
- // ═══════════════════════════════════════════════════
42
+ const CSS = \`
43
+ p, h1, h2, h3, h4, h5, h6, ul, ol, li, div, span {
44
+ unicode-bidi: plaintext;
45
+ text-align: start;
46
+ }
47
+
48
+ [dir="rtl"] ul, [dir="rtl"] ol {
49
+ padding-left: 0 !important;
50
+ padding-right: 1.5rem !important;
51
+ }
52
+
53
+ pre, code, pre *, code * {
54
+ unicode-bidi: isolate !important;
55
+ direction: ltr !important;
56
+ text-align: left !important;
57
+ }
58
+
59
+ #rtl-toggle-btn {
60
+ position: fixed;
61
+ bottom: 20px;
62
+ right: 20px;
63
+ z-index: 999999;
64
+ width: 50px;
65
+ height: 50px;
66
+ border-radius: 50%;
67
+ background: rgba(60, 60, 60, 0.9);
68
+ border: 2px solid rgba(100, 100, 100, 0.5);
69
+ color: white;
70
+ cursor: pointer;
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ font-size: 24px;
75
+ transition: all 0.3s;
76
+ box-shadow: 0 2px 10px rgba(0,0,0,0.3);
77
+ }
78
+
79
+ #rtl-toggle-btn:hover {
80
+ background: rgba(80, 80, 80, 0.95);
81
+ transform: scale(1.1);
82
+ }
83
+
84
+ #rtl-toggle-btn.active {
85
+ background: rgba(70, 130, 180, 0.9);
86
+ border-color: rgba(70, 130, 180, 0.8);
87
+ }
88
+ \`;
99
89
 
100
- function saveConfig() {
101
- const config = {
102
- faFont: document.getElementById('rtl-fa-font')?.value.trim() || '',
103
- enFont: document.getElementById('rtl-en-font')?.value.trim() || '',
104
- codeFont: document.getElementById('rtl-code-font')?.value.trim() || '',
105
- lineHeight: document.getElementById('rtl-lh-slider')?.value || '1.6',
106
- fontSize: document.getElementById('rtl-fs-slider')?.value || '16',
107
- rtlEnabled: rtlEnabled,
108
- forceRTL: forceRTL,
109
- fixAtSign: fixAtSign
110
- };
111
- console.log('RTL_CONFIG_SAVE:' + JSON.stringify(config));
112
- }
90
+ const styleEl = document.createElement('style');
91
+ styleEl.id = 'rtl-main-style';
92
+ styleEl.textContent = CSS;
93
+ document.head.appendChild(styleEl);
113
94
 
114
95
  function detectRTL(text) {
115
96
  if (!text || text.trim().length === 0) return false;
116
97
  const cleaned = text.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
117
98
  if (cleaned.length === 0) return false;
118
99
 
119
- // Check first meaningful character
120
100
  const firstChar = cleaned.match(/[A-Za-z\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/);
121
101
  if (!firstChar) return false;
122
102
 
123
- const isPersianArabic = /[\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(firstChar[0]);
124
- return isPersianArabic;
103
+ return /[\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(firstChar[0]);
125
104
  }
126
105
 
127
- // ═══════════════════════════════════════════════════
128
- // Dynamic CSS Generator
129
- // ═══════════════════════════════════════════════════
130
-
131
- function generateCSS(faFont, enFont, codeFont, lh, fs) {
132
- let faFontFamily = "'VazirmatnFallback'";
133
- let faFontRule = '';
134
-
135
- if (faFont) {
136
- faFontFamily = "'CustomPersianFont', 'VazirmatnFallback'";
137
- const baseName = faFont.replace(/[-\\s]?Regular$/i, '');
138
- faFontRule = \`
139
- @font-face {
140
- font-family: 'CustomPersianFont';
141
- src: local('\${faFont}'), local('\${baseName}');
142
- font-weight: 400;
143
- unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
144
- }
145
- @font-face {
146
- font-family: 'CustomPersianFont';
147
- src: local('\${baseName} Bold'), local('\${baseName}-Bold'), local('\${baseName}Bold');
148
- font-weight: 700;
149
- unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
150
- }
151
- \`;
152
- }
153
-
154
- const enFontStr = enFont ? \`'\${enFont}', ui-sans-serif, system-ui, sans-serif\` : 'ui-sans-serif, system-ui, sans-serif';
155
- const codeFontStr = codeFont ? \`'\${codeFont}', ui-monospace, 'Courier New', monospace\` : 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace';
156
-
157
- const forceRTLStyles = forceRTL ? \`
158
- .prose > *:not(pre):not(code),
159
- [data-testid="chat-message"] > *:not(pre):not(code),
160
- .markdown-body > *:not(pre):not(code),
161
- .leading-relaxed > *:not(pre):not(code),
162
- [data-testid="user-input-step"],
163
- [data-testid="user-input-step"] > *:not(pre):not(code),
164
- div:has(> [role="radiogroup"]),
165
- label[for^="ask-opt-"] {
166
- direction: rtl !important;
167
- text-align: right !important;
168
- unicode-bidi: isolate !important;
169
- }
170
- \` : '';
171
-
172
- return \`
173
- \${faFontRule}
174
-
175
- @font-face {
176
- font-family: 'VazirmatnFallback';
177
- src: url('data:font/woff2;base64,\${FONT_BASE64}') format('woff2');
178
- font-weight: 100 900;
179
- unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
180
- }
181
-
182
- :root, :host, html, body {
183
- font-family: \${faFontFamily}, \${enFontStr}, "Apple Color Emoji", "Segoe UI Emoji" !important;
184
- }
185
-
186
- .prose, [data-testid="chat-message"], .markdown-body,
187
- .leading-relaxed, [contenteditable="true"], [contenteditable="true"] p {
188
- font-size: \${fs}px !important;
189
- }
190
-
191
- p, h1, h2, h3, h4, h5, h6, ul, ol {
192
- unicode-bidi: plaintext;
193
- text-align: start;
194
- }
195
-
196
- .prose > *, [data-testid="chat-message"] > *, .markdown-body > * {
197
- unicode-bidi: plaintext;
198
- text-align: start;
199
- }
200
-
201
- label[for^="ask-opt-"] {
202
- unicode-bidi: plaintext;
203
- text-align: start;
204
- }
205
-
206
- label[for^="ask-opt-"][dir="rtl"] {
207
- direction: rtl;
208
- text-align: right;
209
- }
210
-
211
- textarea[data-testid="ask-question-writein"] {
212
- unicode-bidi: plaintext;
213
- text-align: start;
214
- }
215
-
216
- \${forceRTLStyles}
217
-
218
- /* RTL List Padding */
219
- ul:not(#_)[dir="rtl"], ol:not(#_)[dir="rtl"],
220
- [dir="rtl"] ul:not(#_), [dir="rtl"] ol:not(#_) {
221
- padding-left: 0 !important;
222
- padding-right: 1.25rem !important;
223
- }
224
-
225
- [dir="rtl"] ul:not(#_) ul:not(#_), [dir="rtl"] ul:not(#_) ol:not(#_),
226
- [dir="rtl"] ol:not(#_) ul:not(#_), [dir="rtl"] ol:not(#_) ol:not(#_) {
227
- padding-left: 0 !important;
228
- padding-right: 2.5rem !important;
229
- }
230
-
231
- /* Keep thinking blocks LTR */
232
- .cursor-edit.text-secondary-foreground,
233
- .cursor-edit.text-secondary-foreground * {
234
- direction: ltr !important;
235
- text-align: left !important;
236
- unicode-bidi: isolate !important;
237
- }
238
-
239
- /* Code blocks always LTR */
240
- pre, code, pre *, code * {
241
- unicode-bidi: isolate !important;
242
- direction: ltr !important;
243
- text-align: left !important;
244
- font-family: \${codeFontStr} !important;
245
- }
246
-
247
- /* Line height control */
248
- .leading-relaxed {
249
- line-height: \${lh} !important;
250
- }
251
-
252
- [contenteditable="true"], [contenteditable="true"] * {
253
- unicode-bidi: isolate !important;
254
- text-align: start !important;
255
- }
256
-
257
- /* Smart auto-direction */
258
- [role="navigation"][aria-label="Sidebar"] *, .truncate {
259
- unicode-bidi: plaintext !important;
260
- text-align: start !important;
261
- }
262
-
263
- /* Apply line height to chat */
264
- .prose p, .prose li, .markdown-body p,
265
- [data-testid="chat-message"] p,
266
- [data-testid="chat-message"] .leading-relaxed,
267
- .leading-relaxed, [data-testid="user-input-step"],
268
- [data-testid="user-input-step"] div,
269
- [data-lexical-text="true"],
270
- [contenteditable="true"], [contenteditable="true"] p,
271
- label[for^="ask-opt-"] {
272
- line-height: \${lh} !important;
273
- }
274
- \`;
275
- }
276
-
277
- // ═══════════════════════════════════════════════════
278
- // Style Injection
279
- // ═══════════════════════════════════════════════════
280
-
281
- const mainStyleEl = document.createElement('style');
282
- mainStyleEl.id = 'antigravity-rtl-main-style';
283
- document.head.appendChild(mainStyleEl);
284
-
285
- function updateCSS() {
286
- const faFont = document.getElementById('rtl-fa-font')?.value.trim() || '';
287
- const enFont = document.getElementById('rtl-en-font')?.value.trim() || '';
288
- const codeFont = document.getElementById('rtl-code-font')?.value.trim() || '';
289
- const lh = document.getElementById('rtl-lh-slider')?.value || CONFIG.lineHeight;
290
- const fs = document.getElementById('rtl-fs-slider')?.value || CONFIG.fontSize;
291
-
292
- mainStyleEl.textContent = generateCSS(faFont, enFont, codeFont, lh, fs);
293
- }
294
-
295
- // Initial CSS
296
- updateCSS();
297
-
298
- // ═══════════════════════════════════════════════════
299
- // Direction Observer
300
- // ═══════════════════════════════════════════════════
301
-
302
106
  function updateDirections() {
303
107
  if (!rtlEnabled) return;
304
108
 
305
- // Input fields
306
- document.querySelectorAll('[contenteditable="true"] p, [contenteditable="true"], textarea[data-testid="ask-question-writein"]').forEach(el => {
307
- const rawText = el.tagName === 'TEXTAREA' ? el.value : el.textContent;
308
- const text = rawText.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
309
-
310
- if (text.length > 0) {
311
- const isRTL = detectRTL(text);
312
- const newDir = isRTL ? 'rtl' : 'ltr';
313
- if (el.getAttribute('dir') !== newDir) {
314
- el.setAttribute('dir', newDir);
109
+ document.querySelectorAll('[contenteditable="true"], [contenteditable="true"] p, textarea').forEach(el => {
110
+ const text = el.tagName === 'TEXTAREA' ? el.value : el.textContent;
111
+ const cleaned = text.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
112
+
113
+ if (cleaned.length > 0) {
114
+ const dir = detectRTL(cleaned) ? 'rtl' : 'ltr';
115
+ if (el.getAttribute('dir') !== dir) {
116
+ el.setAttribute('dir', dir);
315
117
  }
316
118
  } else {
317
119
  if (el.hasAttribute('dir')) el.removeAttribute('dir');
318
120
  }
319
121
  });
320
122
 
321
- // Chat output & artifacts
322
- document.querySelectorAll(\`
323
- .prose > *,
324
- [data-testid="chat-message"] > *,
325
- .markdown-body > *,
326
- .leading-relaxed > *,
327
- [data-testid="user-input-step"],
328
- [data-testid="user-input-step"] > *,
329
- div:has(> [role="radiogroup"]),
330
- label[for^="ask-opt-"]
331
- \`).forEach(el => {
123
+ document.querySelectorAll('.prose > *, [data-testid="chat-message"] > *, .markdown-body > *, .leading-relaxed > *').forEach(el => {
332
124
  if (el.tagName === 'PRE' || el.tagName === 'CODE') return;
333
125
 
334
126
  const text = el.textContent.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
335
- let dir = 'auto';
336
-
337
- if (forceRTL) {
338
- dir = 'rtl';
339
- } else if (text) {
340
- dir = detectRTL(text) ? 'rtl' : 'ltr';
341
- }
342
-
343
- if (el.getAttribute('dir') !== dir) {
344
- el.setAttribute('dir', dir);
127
+ if (text) {
128
+ const dir = detectRTL(text) ? 'rtl' : 'ltr';
129
+ if (el.getAttribute('dir') !== dir) {
130
+ el.setAttribute('dir', dir);
131
+ }
345
132
  }
346
133
  });
347
134
  }
348
135
 
349
- // Set up observers
350
136
  document.body.addEventListener('input', updateDirections, { capture: true });
351
- document.body.addEventListener('focusin', updateDirections, { capture: true });
352
-
353
- const mutationObserver = new MutationObserver(updateDirections);
354
- mutationObserver.observe(document.body, { childList: true, subtree: true });
355
-
137
+ const observer = new MutationObserver(updateDirections);
138
+ observer.observe(document.body, { childList: true, subtree: true });
356
139
  setInterval(updateDirections, 500);
357
140
 
358
- // ═══════════════════════════════════════════════════
359
- // Keyboard Shortcuts & Fixes
360
- // ═══════════════════════════════════════════════════
361
-
362
141
  document.addEventListener('keydown', (e) => {
363
- // Alt + R to toggle RTL
364
142
  if (e.altKey && e.code === 'KeyR') {
365
143
  e.preventDefault();
366
144
  toggleRTL();
367
145
  }
368
-
369
- // Fix @ sign on Persian keyboard
370
- if (fixAtSign && e.code === 'Digit2' && e.shiftKey) {
371
- if (e.key === '٬' || e.key === '،') {
372
- e.preventDefault();
373
- document.execCommand('insertText', false, '@');
374
- }
375
- }
376
146
  }, { capture: true });
377
147
 
378
- // ═══════════════════════════════════════════════════
379
- // Widget UI Styles
380
- // ═══════════════════════════════════════════════════
381
-
382
- const widgetStyles = document.createElement('style');
383
- widgetStyles.id = 'rtl-widget-styles';
384
- widgetStyles.textContent = \`
385
- .rtl-tooltip {
386
- visibility: hidden;
387
- opacity: 0;
388
- transition: opacity 0.2s;
389
- pointer-events: none;
390
- }
391
- .rtl-info-icon:hover .rtl-tooltip {
392
- visibility: visible;
393
- opacity: 1;
394
- }
395
- .rtl-widget-panel {
396
- transform: scale(0);
397
- opacity: 0;
398
- pointer-events: none;
399
- transition: all 0.3s;
400
- transform-origin: bottom right;
401
- }
402
- .rtl-widget-container:hover .rtl-widget-trigger {
403
- opacity: 0 !important;
404
- transform: scale(0.5) !important;
405
- pointer-events: none !important;
406
- }
407
- .rtl-widget-container:hover .rtl-widget-panel {
408
- transform: scale(1) !important;
409
- opacity: 1 !important;
410
- pointer-events: auto !important;
411
- }
412
- :root {
413
- --rtl-bg: #ffffff;
414
- --rtl-text: #111827;
415
- --rtl-border: #e5e7eb;
416
- --rtl-input-bg: #f3f4f6;
417
- }
418
- :root.dark, .dark {
419
- --rtl-bg: #1e293b;
420
- --rtl-text: #f3f4f6;
421
- --rtl-border: #334155;
422
- --rtl-input-bg: #334155;
423
- }
424
- @media (prefers-color-scheme: dark) {
425
- :root:not(.light) {
426
- --rtl-bg: #1e293b;
427
- --rtl-text: #f3f4f6;
428
- --rtl-border: #334155;
429
- --rtl-input-bg: #334155;
430
- }
431
- }
432
- .rtl-theme-panel {
433
- background-color: var(--rtl-bg) !important;
434
- color: var(--rtl-text) !important;
435
- border: 1px solid var(--rtl-border) !important;
436
- }
437
- .rtl-theme-input {
438
- background-color: var(--rtl-input-bg) !important;
439
- color: var(--rtl-text) !important;
440
- border: 1px solid var(--rtl-border) !important;
441
- }
442
- .w-11 { width: 44px !important; }
443
- .h-6 { height: 24px !important; }
444
- .w-4 { width: 16px !important; }
445
- .h-4 { height: 16px !important; }
446
- .translate-x-6 { transform: translateX(24px) !important; }
447
- .translate-x-1 { transform: translateX(4px) !important; }
448
- .bg-accent { background-color: #4f46e5 !important; }
449
- .rtl-toggle-reset {
450
- padding: 0 !important;
451
- border: none !important;
452
- box-sizing: border-box !important;
453
- min-width: 44px !important;
454
- outline: none !important;
455
- display: inline-flex !important;
456
- align-items: center !important;
457
- }
458
- .rtl-gh-link {
459
- transition: all 0.1s !important;
460
- }
461
- .rtl-gh-link:hover {
462
- color: #eab308 !important;
463
- opacity: 1 !important;
464
- }
465
- \`;
466
- document.head.appendChild(widgetStyles);
467
-
468
- // ═══════════════════════════════════════════════════
469
- // Widget UI HTML
470
- // ═══════════════════════════════════════════════════
148
+ const btn = document.createElement('button');
149
+ btn.id = 'rtl-toggle-btn';
150
+ btn.className = rtlEnabled ? 'active' : '';
151
+ btn.innerHTML = '⇄';
152
+ btn.title = 'Toggle RTL (Alt+R)';
471
153
 
472
- const widgetHTML = \`
473
- <div class="rtl-widget-container group fixed bottom-4 right-4 w-10 h-10" style="direction: ltr; z-index: 999999;">
474
- <div class="rtl-widget-trigger relative w-10 h-10 flex items-center justify-center rounded-full bg-secondary text-secondary-foreground hover:text-foreground cursor-pointer opacity-80 transition-all duration-300">
475
- <svg height="20" width="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
476
- </div>
477
- <div class="rtl-widget-panel rtl-theme-panel absolute bottom-0 right-0 flex flex-col p-px rounded-2xl text-sm w-60">
478
- <div class="flex flex-col gap-2 p-3 rounded-[15px]">
479
- <div class="text-center px-1 pb-2 mb-1 border-b border-border border-opacity-50">
480
- <span class="text-base font-semibold">Antigravity Smart RTL</span>
481
- </div>
482
- <div class="flex items-center justify-between gap-4 px-1">
483
- <div class="flex items-center">
484
- <span id="rtl-status-text" class="font-medium text-xs opacity-80">\${rtlEnabled ? 'Enabled' : 'Disabled'}</span>
485
- <div class="relative flex items-center rtl-info-icon ml-1">
486
- <span class="cursor-pointer inline-flex items-center text-muted-foreground hover:text-foreground">
487
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 -960 960 960" fill="currentColor" class="w-3.5 h-3.5"><path d="M450-290h60V-520H450v230Zm52.92-307.75q9.38-9.29 9.38-23.02t-9.29-23.02T480-653.07t-23.02,9.29t-9.29,23.02t9.38,23.02T480-588.46t22.92-9.29ZM480.07-100q-78.84,0-148.2-29.92T211.18-211.13T129.93-331.76T100-479.93t29.92-148.2t81.21-120.68t120.63-81.25T479.93-860t148.2,29.92t120.68,81.21t81.25,120.63T860-480.07t-29.92,148.2T748.87-211.18T628.24-129.93T480.07-100ZM480-160q134,0 227-93t93-227T707-707T480-800T253-707T160-480t93,227t227,93Zm0-320Z"/></svg>
488
- </span>
489
- <div class="rtl-tooltip absolute bottom-full left-1/2 -translate-x-1/2 mb-2 w-32 p-1.5 rounded shadow-md z-50 text-center bg-muted border border-border text-foreground text-[11px]">
490
- Shortcut: Alt + R
491
- <div class="absolute top-full left-1/2 -translate-x-1/2 w-0 h-0" style="border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid var(--border);"></div>
492
- </div>
493
- </div>
494
- </div>
495
- <button id="rtl-main-toggle" type="button" class="rtl-toggle-reset relative rounded-full transition-colors h-6 w-11 \${rtlEnabled ? 'bg-accent' : 'bg-gray-400 bg-opacity-40'} cursor-pointer">
496
- <span class="inline-block rounded-full bg-white transition-transform shadow-sm h-4 w-4" style="transform: translateX(\${rtlEnabled ? '24px' : '4px'});"></span>
497
- </button>
498
- </div>
499
- <div id="rtl-settings-area" class="flex flex-col gap-2 transition-all \${rtlEnabled ? '' : 'opacity-40 pointer-events-none'}">
500
- <div class="flex items-center justify-between gap-2 px-1 mt-1">
501
- <span class="font-medium text-xs opacity-80">Force RTL</span>
502
- <button id="rtl-force-toggle" type="button" class="rtl-toggle-reset relative rounded-full transition-colors h-6 w-11 \${forceRTL ? 'bg-accent' : 'bg-gray-400 bg-opacity-40'} cursor-pointer">
503
- <span class="inline-block rounded-full bg-white transition-transform shadow-sm h-4 w-4" style="transform: translateX(\${forceRTL ? '24px' : '4px'});"></span>
504
- </button>
505
- </div>
506
- <div class="h-px bg-border border-opacity-30 w-full my-1"></div>
507
- <div class="flex items-center justify-between gap-2 px-1">
508
- <span class="font-medium text-xs opacity-80">FA/AR Font</span>
509
- <input id="rtl-fa-font" type="text" placeholder="Vazirmatn" value="\${CONFIG.faFont}" class="rtl-theme-input text-[11px] px-2 py-1 rounded-md w-28 focus:outline-none">
510
- </div>
511
- <div class="flex items-center justify-between gap-2 px-1 mt-1">
512
- <span class="font-medium text-xs opacity-80">EN Font</span>
513
- <input id="rtl-en-font" type="text" placeholder="System" value="\${CONFIG.enFont}" class="rtl-theme-input text-[11px] px-2 py-1 rounded-md w-28 focus:outline-none">
514
- </div>
515
- <div class="flex items-center justify-between gap-2 px-1 mt-1">
516
- <span class="font-medium text-xs opacity-80">Code Font</span>
517
- <input id="rtl-code-font" type="text" placeholder="System" value="\${CONFIG.codeFont}" class="rtl-theme-input text-[11px] px-2 py-1 rounded-md w-28 focus:outline-none">
518
- </div>
519
- <div class="flex items-center justify-between gap-2 px-1 mt-1">
520
- <span class="font-medium text-xs opacity-80">Line Height</span>
521
- <div class="flex items-center gap-2">
522
- <input id="rtl-lh-slider" type="range" min="1.2" max="2.5" step="0.1" value="\${CONFIG.lineHeight}" class="h-1 w-20 cursor-pointer">
523
- <button id="rtl-lh-reset" type="button" class="opacity-50 hover:opacity-100 transition-opacity cursor-pointer" title="Reset">
524
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
525
- </button>
526
- </div>
527
- </div>
528
- <div class="flex items-center justify-between gap-2 px-1 mt-1 mb-1">
529
- <span class="font-medium text-xs opacity-80">Font Size</span>
530
- <div class="flex items-center gap-2">
531
- <input id="rtl-fs-slider" type="range" min="11" max="22" step="1" value="\${CONFIG.fontSize}" class="h-1 w-20 cursor-pointer">
532
- <button id="rtl-fs-reset" type="button" class="opacity-50 hover:opacity-100 transition-opacity cursor-pointer" title="Reset">
533
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
534
- </button>
535
- </div>
536
- </div>
537
- <div class="h-px bg-border border-opacity-30 w-full my-1"></div>
538
- <div class="flex items-center justify-between gap-2 px-1 mb-1">
539
- <span class="font-medium text-xs opacity-80">Type @ with Shift+2</span>
540
- <button id="rtl-at-toggle" type="button" class="rtl-toggle-reset relative rounded-full transition-colors h-6 w-11 \${fixAtSign ? 'bg-accent' : 'bg-gray-400 bg-opacity-40'} cursor-pointer">
541
- <span class="inline-block rounded-full bg-white transition-transform shadow-sm h-4 w-4" style="transform: translateX(\${fixAtSign ? '24px' : '4px'});"></span>
542
- </button>
543
- </div>
544
- </div>
545
- <div class="h-px bg-border w-full"></div>
546
- <a href="https://github.com/VaFa1726/antigravity-rtl-patcher" target="_blank" class="rtl-gh-link flex items-center justify-center gap-2 text-xs font-semibold opacity-70 no-underline pt-1 pb-0.5">
547
- <svg height="14" width="14" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"/></svg>
548
- Star on GitHub
549
- </a>
550
- </div>
551
- </div>
552
- </div>
553
- \`;
554
-
555
- // Insert widget
556
- const widgetWrapper = document.createElement('div');
557
- widgetWrapper.innerHTML = widgetHTML;
558
- document.body.appendChild(widgetWrapper.firstElementChild);
559
-
560
- // ═══════════════════════════════════════════════════
561
- // Event Handlers
562
- // ═══════════════════════════════════════════════════
154
+ btn.addEventListener('click', toggleRTL);
563
155
 
564
156
  function toggleRTL() {
565
157
  rtlEnabled = !rtlEnabled;
566
- const statusText = document.getElementById('rtl-status-text');
567
- const mainToggle = document.getElementById('rtl-main-toggle');
568
- const settingsArea = document.getElementById('rtl-settings-area');
569
-
570
- statusText.textContent = rtlEnabled ? 'Enabled' : 'Disabled';
571
158
 
572
159
  if (rtlEnabled) {
573
- mainToggle.classList.add('bg-accent');
574
- mainToggle.classList.remove('bg-gray-400', 'bg-opacity-40');
575
- mainToggle.querySelector('span').style.transform = 'translateX(24px)';
576
- settingsArea.classList.remove('opacity-40', 'pointer-events-none');
577
- if (!document.getElementById('antigravity-rtl-main-style')) {
578
- document.head.appendChild(mainStyleEl);
160
+ btn.classList.add('active');
161
+ if (!document.getElementById('rtl-main-style')) {
162
+ document.head.appendChild(styleEl);
579
163
  }
580
- updateCSS();
581
164
  updateDirections();
582
165
  } else {
583
- mainToggle.classList.remove('bg-accent');
584
- mainToggle.classList.add('bg-gray-400', 'bg-opacity-40');
585
- mainToggle.querySelector('span').style.transform = 'translateX(4px)';
586
- settingsArea.classList.add('opacity-40', 'pointer-events-none');
587
- if (mainStyleEl.parentNode) {
588
- mainStyleEl.parentNode.removeChild(mainStyleEl);
166
+ btn.classList.remove('active');
167
+ if (styleEl.parentNode) {
168
+ styleEl.parentNode.removeChild(styleEl);
589
169
  }
590
170
  document.querySelectorAll('[dir]').forEach(el => {
591
- if (!el.closest('.rtl-widget-container')) {
171
+ if (!el.closest('#rtl-toggle-btn')) {
592
172
  el.removeAttribute('dir');
593
173
  }
594
174
  });
595
175
  }
596
176
 
597
- saveConfig();
177
+ console.log('RTL_CONFIG_SAVE:' + JSON.stringify({ enabled: rtlEnabled }));
598
178
  }
599
179
 
600
- document.getElementById('rtl-main-toggle').addEventListener('click', toggleRTL);
601
-
602
- document.getElementById('rtl-force-toggle').addEventListener('click', () => {
603
- forceRTL = !forceRTL;
604
- const btn = document.getElementById('rtl-force-toggle');
605
- if (forceRTL) {
606
- btn.classList.add('bg-accent');
607
- btn.classList.remove('bg-gray-400', 'bg-opacity-40');
608
- btn.querySelector('span').style.transform = 'translateX(24px)';
609
- } else {
610
- btn.classList.remove('bg-accent');
611
- btn.classList.add('bg-gray-400', 'bg-opacity-40');
612
- btn.querySelector('span').style.transform = 'translateX(4px)';
613
- }
614
- updateCSS();
615
- updateDirections();
616
- saveConfig();
617
- });
618
-
619
- document.getElementById('rtl-at-toggle').addEventListener('click', () => {
620
- fixAtSign = !fixAtSign;
621
- const btn = document.getElementById('rtl-at-toggle');
622
- if (fixAtSign) {
623
- btn.classList.add('bg-accent');
624
- btn.classList.remove('bg-gray-400', 'bg-opacity-40');
625
- btn.querySelector('span').style.transform = 'translateX(24px)';
626
- } else {
627
- btn.classList.remove('bg-accent');
628
- btn.classList.add('bg-gray-400', 'bg-opacity-40');
629
- btn.querySelector('span').style.transform = 'translateX(4px)';
630
- }
631
- saveConfig();
632
- });
633
-
634
- // Font inputs
635
- ['rtl-fa-font', 'rtl-en-font', 'rtl-code-font'].forEach(id => {
636
- document.getElementById(id).addEventListener('input', () => {
637
- updateCSS();
638
- saveConfig();
639
- });
640
- });
641
-
642
- // Sliders
643
- document.getElementById('rtl-lh-slider').addEventListener('input', () => {
644
- updateCSS();
645
- saveConfig();
646
- });
647
-
648
- document.getElementById('rtl-fs-slider').addEventListener('input', () => {
649
- updateCSS();
650
- saveConfig();
651
- });
652
-
653
- // Reset buttons
654
- document.getElementById('rtl-lh-reset').addEventListener('click', () => {
655
- document.getElementById('rtl-lh-slider').value = '1.6';
656
- updateCSS();
657
- saveConfig();
658
- });
659
-
660
- document.getElementById('rtl-fs-reset').addEventListener('click', () => {
661
- document.getElementById('rtl-fs-slider').value = '16';
662
- updateCSS();
663
- saveConfig();
664
- });
665
-
666
- // ═══════════════════════════════════════════════════
667
- // Initialization Complete
668
- // ═══════════════════════════════════════════════════
180
+ document.body.appendChild(btn);
669
181
 
670
182
  if (rtlEnabled) {
671
183
  updateDirections();
672
184
  }
673
-
674
- console.log('[RTL Engine] Initialization complete ✓');
675
185
  })();
676
- `).catch(err => {
677
- console.error('[RTL] Failed to inject engine:', err);
678
- });
186
+ `).catch(err => console.error('[RTL] Injection failed:', err));
679
187
 
680
188
  } catch (error) {
681
- console.error('[RTL] Injection error:', error);
189
+ console.error('[RTL] Init error:', error);
682
190
  }
683
191
  });
package/src/patcher.js CHANGED
@@ -23,7 +23,8 @@ async function isAlreadyPatched(extractDir) {
23
23
  }
24
24
 
25
25
  const content = await fs.readFile(utilsPath, 'utf-8');
26
- return content.includes(PATCH_MARKER);
26
+ // Always return false to force re-patching with new version
27
+ return false;
27
28
  }
28
29
 
29
30
  /**