antigravity-rtl-patcher 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 +77 -0
- package/bin/cli.js +38 -0
- package/package.json +32 -0
- package/payload/rtl-engine.js +73 -0
- package/payload/styles.css +20 -0
- package/src/patcher.js +151 -0
- package/src/paths.js +37 -0
- package/src/utils.js +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# š Antigravity RTL Patcher
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<img src="https://img.shields.io/npm/v/antigravity-rtl-patcher?color=cyan&label=Version&style=for-the-badge" alt="Version">
|
|
5
|
+
<img src="https://img.shields.io/npm/dt/antigravity-rtl-patcher?color=magenta&style=for-the-badge" alt="Downloads">
|
|
6
|
+
<img src="https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge" alt="License">
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<br>
|
|
10
|
+
|
|
11
|
+
<div align="center">
|
|
12
|
+
<h3>An elegant, intelligent, and seamless RTL & Typography patcher for Antigravity IDE.</h3>
|
|
13
|
+
<p>Bring native support for Persian, Arabic, and Hebrew to your favorite AI IDE.</p>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## ā” What is this?
|
|
19
|
+
Antigravity IDE (like many modern AI editors) is built on Electron. Out of the box, it lacks proper Right-to-Left (RTL) support. When AI generates Persian or Arabic text, the alignment breaks, fonts look terrible, and mixed English/RTL sentences become unreadable.
|
|
20
|
+
|
|
21
|
+
This tool is a **CLI Patcher**. It deeply hooks into the core of Antigravity IDE (`app.asar`), injects a smart JavaScript `MutationObserver` engine, and automatically formats text direction dynamically.
|
|
22
|
+
|
|
23
|
+
## š Features
|
|
24
|
+
- **š§ Smart Direction:** Detects RTL languages using Regex and applies alignment only where necessary.
|
|
25
|
+
- **šØ Beautiful Typography:** Automatically injects the modern **Vazirmatn** font for perfect legibility.
|
|
26
|
+
- **š§© Mixed Text Support:** Uses `unicode-bidi: plaintext` to ensure English code blocks inside Persian text don't break.
|
|
27
|
+
- **š”ļø Safe & Reversible:** Automatically creates a backup. You can restore the IDE to its original state with a single command.
|
|
28
|
+
- **āļø OS Agnostic:** Works on Windows, macOS, and Linux out of the box.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## š¦ Installation & Usage
|
|
33
|
+
|
|
34
|
+
You don't even need to download the repository. Just run it directly via `npx`!
|
|
35
|
+
|
|
36
|
+
### 1. Patch the IDE
|
|
37
|
+
To inject RTL support, run the following command in your terminal:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# macOS & Linux (Requires sudo to modify application files)
|
|
41
|
+
sudo npx antigravity-rtl-patcher patch
|
|
42
|
+
|
|
43
|
+
# Windows (Run PowerShell as Administrator)
|
|
44
|
+
npx antigravity-rtl-patcher patch
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Restore (Unpatch)
|
|
48
|
+
If you want to remove the patch or an update breaks something, you can easily restore from the backup:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# macOS & Linux
|
|
52
|
+
sudo npx antigravity-rtl-patcher restore
|
|
53
|
+
|
|
54
|
+
# Windows
|
|
55
|
+
npx antigravity-rtl-patcher restore
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
*(Note: Whenever Antigravity IDE updates, the patch will be overwritten. Just run the `patch` command again!)*
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## š ļø Architecture
|
|
63
|
+
|
|
64
|
+
This project is divided into two main parts:
|
|
65
|
+
1. **The Patcher (`src/patcher.js`)**: A Node.js CLI that locates the `app.asar` file, extracts it to a temporary directory, injects our payload into the main `index.html`, and repacks it.
|
|
66
|
+
2. **The Payload (`payload/`)**: A combination of smart CSS and Vanilla JavaScript that runs inside the Electron UI. It uses a `MutationObserver` to watch for new chat messages dynamically generated by the AI and styles them on the fly.
|
|
67
|
+
|
|
68
|
+
## š¤ Contributing
|
|
69
|
+
Contributions, issues, and feature requests are welcome!
|
|
70
|
+
Feel free to check [issues page](https://github.com/VaFa1726/antigravity-rtl-patcher/issues).
|
|
71
|
+
|
|
72
|
+
## š License
|
|
73
|
+
This project is [MIT](https://choosealicense.com/licenses/mit/) licensed.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
<div align="center">
|
|
77
|
+
</div>
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { patch, restore } = require('../src/patcher');
|
|
6
|
+
|
|
7
|
+
program
|
|
8
|
+
.name('agy-rtl')
|
|
9
|
+
.description('RTL & Typography patcher for Antigravity IDE')
|
|
10
|
+
.version('1.0.0');
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.command('patch')
|
|
14
|
+
.description('Inject RTL support into Antigravity IDE')
|
|
15
|
+
.action(async () => {
|
|
16
|
+
try {
|
|
17
|
+
console.log(chalk.cyan.bold('\nš Starting Antigravity RTL Patcher...'));
|
|
18
|
+
await patch();
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error(chalk.red('\nā Patch failed:'), err.message);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
program
|
|
26
|
+
.command('restore')
|
|
27
|
+
.description('Restore Antigravity IDE to its original state')
|
|
28
|
+
.action(async () => {
|
|
29
|
+
try {
|
|
30
|
+
console.log(chalk.yellow.bold('\nš Restoring Antigravity...'));
|
|
31
|
+
await restore();
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error(chalk.red('\nā Restore failed:'), err.message);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "antigravity-rtl-patcher",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "An elegant RTL and typography patcher for Antigravity IDE based on Electron",
|
|
5
|
+
"main": "src/patcher.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agy-rtl": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node ./bin/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"antigravity",
|
|
14
|
+
"rtl",
|
|
15
|
+
"farsi",
|
|
16
|
+
"arabic",
|
|
17
|
+
"hebrew",
|
|
18
|
+
"patcher",
|
|
19
|
+
"electron",
|
|
20
|
+
"asar"
|
|
21
|
+
],
|
|
22
|
+
"author": "VaFa1726",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@electron/asar": "^3.2.14",
|
|
26
|
+
"chalk": "^4.1.2",
|
|
27
|
+
"commander": "^11.1.0",
|
|
28
|
+
"fs-extra": "^11.2.0",
|
|
29
|
+
"ora": "^5.4.1",
|
|
30
|
+
"sudo-prompt": "^9.2.1"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
console.log('š AGY RTL Engine Initialized');
|
|
3
|
+
|
|
4
|
+
// Regex to detect RTL characters (Arabic, Persian, Hebrew)
|
|
5
|
+
const rtlRegex = /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/;
|
|
6
|
+
|
|
7
|
+
function isRTL(text) {
|
|
8
|
+
// Basic heuristic: check if any RTL char exists
|
|
9
|
+
return rtlRegex.test(text);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function applyRTL(element) {
|
|
13
|
+
// Only process text nodes or direct containers
|
|
14
|
+
const textContent = element.textContent || element.innerText || '';
|
|
15
|
+
|
|
16
|
+
if (isRTL(textContent)) {
|
|
17
|
+
element.setAttribute('data-agy-rtl', 'true');
|
|
18
|
+
element.style.direction = 'rtl';
|
|
19
|
+
element.style.textAlign = 'start';
|
|
20
|
+
|
|
21
|
+
// Crucial for mixed English/Farsi content (like code snippets in Farsi text)
|
|
22
|
+
element.style.unicodeBidi = 'plaintext';
|
|
23
|
+
|
|
24
|
+
// Mark as processed
|
|
25
|
+
element.classList.add('agy-rtl-processed');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Observe DOM mutations for dynamically added chat messages
|
|
30
|
+
const observer = new MutationObserver((mutations) => {
|
|
31
|
+
mutations.forEach((mutation) => {
|
|
32
|
+
if (mutation.addedNodes.length) {
|
|
33
|
+
mutation.addedNodes.forEach((node) => {
|
|
34
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
35
|
+
// Apply logic to the node itself if it has text
|
|
36
|
+
if (node.textContent && node.textContent.trim().length > 0) {
|
|
37
|
+
// We should probably target specific chat bubble selectors here if we knew them.
|
|
38
|
+
// For a generic approach, we look for paragraphs or divs with raw text.
|
|
39
|
+
const elementsToScan = node.querySelectorAll('p, span, div.message-content, div.chat-bubble, li, h1, h2, h3');
|
|
40
|
+
elementsToScan.forEach(el => {
|
|
41
|
+
if (!el.classList.contains('agy-rtl-processed')) {
|
|
42
|
+
applyRTL(el);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Also check the root node added
|
|
47
|
+
if (!node.classList.contains('agy-rtl-processed')) {
|
|
48
|
+
applyRTL(node);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Start observing
|
|
58
|
+
window.addEventListener('load', () => {
|
|
59
|
+
observer.observe(document.body, {
|
|
60
|
+
childList: true,
|
|
61
|
+
subtree: true,
|
|
62
|
+
characterData: true
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Initial scan
|
|
66
|
+
document.querySelectorAll('p, span, div, li, h1, h2, h3').forEach(el => {
|
|
67
|
+
if (el.textContent && el.textContent.trim().length > 0 && !el.children.length) {
|
|
68
|
+
applyRTL(el);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
})();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* Import a modern Persian font from Google Fonts (Vazirmatn) */
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
|
|
3
|
+
|
|
4
|
+
/* Apply font to patched elements */
|
|
5
|
+
[data-agy-rtl="true"] {
|
|
6
|
+
font-family: 'Vazirmatn', system-ui, -apple-system, sans-serif !important;
|
|
7
|
+
line-height: 1.8 !important;
|
|
8
|
+
letter-spacing: normal !important;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* Fix code blocks inside RTL text */
|
|
12
|
+
[data-agy-rtl="true"] code,
|
|
13
|
+
[data-agy-rtl="true"] pre {
|
|
14
|
+
direction: ltr !important;
|
|
15
|
+
text-align: left !important;
|
|
16
|
+
unicode-bidi: isolate !important;
|
|
17
|
+
font-family: monospace !important;
|
|
18
|
+
display: inline-block;
|
|
19
|
+
margin: 0 4px;
|
|
20
|
+
}
|
package/src/patcher.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const asar = require('@electron/asar');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const ora = require('ora');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const { getAsarPath } = require('./paths');
|
|
8
|
+
const { checkPermissions, delay } = require('./utils');
|
|
9
|
+
|
|
10
|
+
async function patch() {
|
|
11
|
+
checkPermissions();
|
|
12
|
+
|
|
13
|
+
const spinner = ora('Locating Antigravity IDE...').start();
|
|
14
|
+
let asarPath;
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
asarPath = getAsarPath();
|
|
18
|
+
spinner.succeed(`Found Antigravity at: ${chalk.gray(asarPath)}`);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
spinner.fail(err.message);
|
|
21
|
+
throw err;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const backupPath = `${asarPath}.backup`;
|
|
25
|
+
const tmpDir = path.join(os.tmpdir(), 'agy-patch-tmp');
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// 1. Backup
|
|
29
|
+
spinner.start('Creating backup...');
|
|
30
|
+
if (!fs.existsSync(backupPath)) {
|
|
31
|
+
await fs.copy(asarPath, backupPath);
|
|
32
|
+
spinner.succeed('Backup created successfully.');
|
|
33
|
+
} else {
|
|
34
|
+
spinner.info('Backup already exists, skipping.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. Extract
|
|
38
|
+
spinner.start('Extracting core files...');
|
|
39
|
+
if (fs.existsSync(tmpDir)) {
|
|
40
|
+
await fs.remove(tmpDir);
|
|
41
|
+
}
|
|
42
|
+
await fs.ensureDir(tmpDir);
|
|
43
|
+
asar.extractAll(asarPath, tmpDir);
|
|
44
|
+
spinner.succeed('Core files extracted.');
|
|
45
|
+
|
|
46
|
+
// 3. Inject Payload
|
|
47
|
+
spinner.start('Injecting RTL engine & typography...');
|
|
48
|
+
|
|
49
|
+
// Find the main HTML file - usually index.html in the root or a dist folder
|
|
50
|
+
const possibleHtmlPaths = [
|
|
51
|
+
path.join(tmpDir, 'index.html'),
|
|
52
|
+
path.join(tmpDir, 'out', 'index.html'),
|
|
53
|
+
path.join(tmpDir, 'dist', 'index.html')
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
let targetHtml = null;
|
|
57
|
+
for (const p of possibleHtmlPaths) {
|
|
58
|
+
if (fs.existsSync(p)) {
|
|
59
|
+
targetHtml = p;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!targetHtml) {
|
|
65
|
+
throw new Error('Could not find the main HTML file to inject.');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let htmlContent = await fs.readFile(targetHtml, 'utf-8');
|
|
69
|
+
|
|
70
|
+
// Read payload files
|
|
71
|
+
const engineCode = await fs.readFile(path.join(__dirname, '..', 'payload', 'rtl-engine.js'), 'utf-8');
|
|
72
|
+
const stylesCode = await fs.readFile(path.join(__dirname, '..', 'payload', 'styles.css'), 'utf-8');
|
|
73
|
+
|
|
74
|
+
// Check if already patched
|
|
75
|
+
if (htmlContent.includes('agy-rtl-engine')) {
|
|
76
|
+
spinner.info('IDE is already patched.');
|
|
77
|
+
await fs.remove(tmpDir);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const injection = `
|
|
82
|
+
<!-- AGY RTL PATCH -->
|
|
83
|
+
<style id="agy-rtl-styles">${stylesCode}</style>
|
|
84
|
+
<script id="agy-rtl-engine">${engineCode}</script>
|
|
85
|
+
<!-- END AGY RTL PATCH -->
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
// Inject just before </body>
|
|
89
|
+
if (htmlContent.includes('</body>')) {
|
|
90
|
+
htmlContent = htmlContent.replace('</body>', `${injection}\n</body>`);
|
|
91
|
+
} else {
|
|
92
|
+
// Fallback
|
|
93
|
+
htmlContent += injection;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await fs.writeFile(targetHtml, htmlContent);
|
|
97
|
+
spinner.succeed('Payload injected into UI.');
|
|
98
|
+
|
|
99
|
+
// 4. Repack
|
|
100
|
+
spinner.start('Repacking core files...');
|
|
101
|
+
await delay(500); // Give file system a moment
|
|
102
|
+
await asar.createPackage(tmpDir, asarPath);
|
|
103
|
+
spinner.succeed('Core repacked successfully.');
|
|
104
|
+
|
|
105
|
+
// 5. Cleanup
|
|
106
|
+
spinner.start('Cleaning up...');
|
|
107
|
+
await fs.remove(tmpDir);
|
|
108
|
+
spinner.succeed('Cleanup complete.');
|
|
109
|
+
|
|
110
|
+
console.log(chalk.green.bold('\n⨠Antigravity IDE successfully patched with RTL support!'));
|
|
111
|
+
console.log(chalk.cyan('Please restart Antigravity for the changes to take effect.\n'));
|
|
112
|
+
|
|
113
|
+
} catch (err) {
|
|
114
|
+
spinner.fail('An error occurred during patching.');
|
|
115
|
+
if (fs.existsSync(tmpDir)) {
|
|
116
|
+
await fs.remove(tmpDir);
|
|
117
|
+
}
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function restore() {
|
|
123
|
+
checkPermissions();
|
|
124
|
+
const spinner = ora('Locating Antigravity IDE...').start();
|
|
125
|
+
|
|
126
|
+
let asarPath;
|
|
127
|
+
try {
|
|
128
|
+
asarPath = getAsarPath();
|
|
129
|
+
spinner.succeed(`Found Antigravity at: ${chalk.gray(asarPath)}`);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
spinner.fail(err.message);
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const backupPath = `${asarPath}.backup`;
|
|
136
|
+
|
|
137
|
+
spinner.start('Restoring from backup...');
|
|
138
|
+
if (fs.existsSync(backupPath)) {
|
|
139
|
+
await fs.copy(backupPath, asarPath);
|
|
140
|
+
await fs.remove(backupPath);
|
|
141
|
+
spinner.succeed('Restored successfully.');
|
|
142
|
+
console.log(chalk.green.bold('\n⨠Antigravity IDE restored to original state!'));
|
|
143
|
+
} else {
|
|
144
|
+
spinner.fail('No backup found. The IDE might not be patched or backup was removed.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
module.exports = {
|
|
149
|
+
patch,
|
|
150
|
+
restore
|
|
151
|
+
};
|
package/src/paths.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
function getAsarPath() {
|
|
6
|
+
const platform = os.platform();
|
|
7
|
+
|
|
8
|
+
// Possible paths where the IDE might be installed
|
|
9
|
+
const paths = {
|
|
10
|
+
win32: [
|
|
11
|
+
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'antigravity', 'resources', 'app.asar'),
|
|
12
|
+
path.join(process.env.PROGRAMFILES || '', 'antigravity', 'resources', 'app.asar')
|
|
13
|
+
],
|
|
14
|
+
darwin: [
|
|
15
|
+
'/Applications/Antigravity.app/Contents/Resources/app.asar',
|
|
16
|
+
path.join(os.homedir(), 'Applications', 'Antigravity.app', 'Contents', 'Resources', 'app.asar')
|
|
17
|
+
],
|
|
18
|
+
linux: [
|
|
19
|
+
'/opt/antigravity/resources/app.asar',
|
|
20
|
+
'/usr/local/lib/antigravity/resources/app.asar'
|
|
21
|
+
]
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const possiblePaths = paths[platform] || [];
|
|
25
|
+
|
|
26
|
+
for (const p of possiblePaths) {
|
|
27
|
+
if (fs.existsSync(p)) {
|
|
28
|
+
return p;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new Error('Antigravity installation not found. Please ensure it is installed in the default location.');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
getAsarPath
|
|
37
|
+
};
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
function checkPermissions() {
|
|
4
|
+
const isWindows = process.platform === 'win32';
|
|
5
|
+
|
|
6
|
+
if (!isWindows) {
|
|
7
|
+
// Check if running as root
|
|
8
|
+
const isRoot = process.getuid && process.getuid() === 0;
|
|
9
|
+
if (!isRoot) {
|
|
10
|
+
console.error(chalk.red.bold('\nā ļø Permission Denied!'));
|
|
11
|
+
console.error(chalk.white('Modifying system applications requires administrator privileges.'));
|
|
12
|
+
console.error(chalk.white(`Please run the command with ${chalk.yellow('sudo')}:\n`));
|
|
13
|
+
console.error(chalk.cyan(' sudo npx agy-rtl patch\n'));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function delay(ms) {
|
|
20
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
checkPermissions,
|
|
25
|
+
delay
|
|
26
|
+
};
|