antigravity-autopilot 1.2.0 → 1.4.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/LICENSE +21 -0
- package/README.md +53 -2
- package/cli.js +209 -67
- package/extension.js +283 -106
- package/icon.png +0 -0
- package/package.json +2 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nguyen Hoang (nguyenhx2 or Brian)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Antigravity AutoPilot
|
|
2
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="icon.png" width="128" alt="Antigravity AutoPilot Logo">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
3
7
|
> Automatically execute all tool calls and terminal commands in Antigravity — no manual confirmation needed.
|
|
4
8
|
|
|
5
9
|
[](https://www.npmjs.com/package/antigravity-autopilot)
|
|
6
10
|
[](https://github.com/nguyenhx2/Antigravity-AutoPilot)
|
|
11
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
12
|
|
|
8
13
|
---
|
|
9
14
|
|
|
@@ -17,6 +22,9 @@ Antigravity has an **"Always Proceed"** terminal execution policy, but due to a
|
|
|
17
22
|
- ✅ Non-destructive — creates `.bak` backup before patching
|
|
18
23
|
- ✅ Reversible — restore originals anytime with `--revert`
|
|
19
24
|
- ✅ Available as VS Code Extension **and** CLI (`npx`)
|
|
25
|
+
- 🛡️ 54+ built-in dangerous command presets (Linux/macOS/Windows)
|
|
26
|
+
- 🔘 On/Off toggle for Command Blocking directly from sidebar
|
|
27
|
+
- ⚙️ Fully customizable preset management with Reset Defaults
|
|
20
28
|
|
|
21
29
|
---
|
|
22
30
|
|
|
@@ -49,7 +57,7 @@ Install the extension directly into Antigravity for a UI-based experience (sideb
|
|
|
49
57
|
|
|
50
58
|
```bash
|
|
51
59
|
# Download .vsix from GitHub Releases, then:
|
|
52
|
-
antigravity --install-extension antigravity-autopilot-1.
|
|
60
|
+
antigravity --install-extension antigravity-autopilot-1.4.0.vsix
|
|
53
61
|
```
|
|
54
62
|
|
|
55
63
|
**Extension features:**
|
|
@@ -57,6 +65,49 @@ antigravity --install-extension antigravity-autopilot-1.0.0.vsix
|
|
|
57
65
|
- 📊 Status bar showing current patch state
|
|
58
66
|
- ⌨️ Keyboard shortcut: `Ctrl+Shift+F12`
|
|
59
67
|
- ⚙️ `applyOnStartup` setting for fully automatic operation
|
|
68
|
+
- 🔘 `enabledOnStartup` — toggle AutoPilot active/suspended on launch
|
|
69
|
+
- 🛡️ **Command Blocking On/Off** — toggle dangerous command blocking directly from the sidebar UI
|
|
70
|
+
- 📋 **Preset Management** — view, remove, and reset 54+ built-in dangerous command presets
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🛡️ Dangerous Command Blocking
|
|
75
|
+
|
|
76
|
+
Built-in protection against destructive commands. **54+ preset patterns** covering all major platforms:
|
|
77
|
+
|
|
78
|
+
| Platform | Examples |
|
|
79
|
+
|----------|----------|
|
|
80
|
+
| **Linux/macOS** | `rm -rf /`, `dd of=/dev/sda`, `mkfs`, fork bombs, `curl \| sh`, `chmod 777 -R /` |
|
|
81
|
+
| **macOS** | `diskutil eraseDisk`, `csrutil disable` |
|
|
82
|
+
| **Windows** | `format C:`, `Remove-Item -Recurse C:\`, `bcdedit /deletevalue`, `IEX download-and-exec` |
|
|
83
|
+
|
|
84
|
+
### Sidebar Controls
|
|
85
|
+
|
|
86
|
+
- 🔘 **On/Off Toggle** — enable or disable command blocking with a single switch
|
|
87
|
+
- 📋 **View all presets** — full list of blocked commands with OS badges (LNX/MAC/WIN)
|
|
88
|
+
- ✕ **Remove individual presets** — click the ✕ button to exclude a preset
|
|
89
|
+
- 🔄 **Reset Defaults** — restore all removed presets with one click
|
|
90
|
+
- 📊 **Active count** — always see how many presets are active
|
|
91
|
+
- 🔅 **Visual feedback** — presets section dims when blocking is disabled
|
|
92
|
+
|
|
93
|
+
### Custom Patterns
|
|
94
|
+
|
|
95
|
+
Add your own patterns via Settings:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
"antigravityAutoAccept.dangerousCommandBlocking.customPatterns": [
|
|
99
|
+
"^my-dangerous-script",
|
|
100
|
+
"DROP TABLE"
|
|
101
|
+
]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Action Modes
|
|
105
|
+
|
|
106
|
+
| Mode | Behavior |
|
|
107
|
+
|------|----------|
|
|
108
|
+
| `block` | Block command + show error notification (default) |
|
|
109
|
+
| `warn` | Show warning but allow command to proceed |
|
|
110
|
+
| `log` | Silently log to Output channel |
|
|
60
111
|
|
|
61
112
|
---
|
|
62
113
|
|
|
@@ -88,4 +139,4 @@ Variable names are resolved via regex at runtime, making the patch resilient to
|
|
|
88
139
|
|
|
89
140
|
## License
|
|
90
141
|
|
|
91
|
-
MIT
|
|
142
|
+
[MIT](LICENSE) — Copyright (c) 2026 Nguyen Hoang (nguyenhx2 or Brian)
|
package/cli.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Antigravity AutoPilot — CLI
|
|
5
|
-
*
|
|
6
|
-
* Patches Antigravity's runtime JS bundle so that the
|
|
7
|
-
* "Always Proceed" terminal execution policy actually
|
|
8
|
-
* auto-executes commands without manual confirmation.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
4
|
+
* Antigravity AutoPilot — CLI v1.3.0
|
|
5
|
+
* ====================================
|
|
11
6
|
* npx antigravity-autopilot Apply patch
|
|
12
|
-
* npx antigravity-autopilot --check Check
|
|
13
|
-
* npx antigravity-autopilot --revert Restore
|
|
7
|
+
* npx antigravity-autopilot --check Check status
|
|
8
|
+
* npx antigravity-autopilot --revert Restore originals
|
|
9
|
+
* npx antigravity-autopilot --help Show help
|
|
14
10
|
*/
|
|
15
11
|
|
|
16
12
|
'use strict';
|
|
@@ -19,7 +15,113 @@ const fs = require('fs');
|
|
|
19
15
|
const path = require('path');
|
|
20
16
|
const os = require('os');
|
|
21
17
|
|
|
22
|
-
// ───
|
|
18
|
+
// ─── ANSI Colors (auto-disable when not a TTY) ───────────────────────────────
|
|
19
|
+
|
|
20
|
+
const isTTY = process.stdout.isTTY;
|
|
21
|
+
const c = {
|
|
22
|
+
reset: isTTY ? '\x1b[0m' : '',
|
|
23
|
+
bold: isTTY ? '\x1b[1m' : '',
|
|
24
|
+
dim: isTTY ? '\x1b[2m' : '',
|
|
25
|
+
yellow: isTTY ? '\x1b[33m' : '',
|
|
26
|
+
cyan: isTTY ? '\x1b[36m' : '',
|
|
27
|
+
green: isTTY ? '\x1b[32m' : '',
|
|
28
|
+
red: isTTY ? '\x1b[31m' : '',
|
|
29
|
+
blue: isTTY ? '\x1b[34m' : '',
|
|
30
|
+
magenta: isTTY ? '\x1b[35m' : '',
|
|
31
|
+
white: isTTY ? '\x1b[97m' : '',
|
|
32
|
+
gray: isTTY ? '\x1b[90m' : '',
|
|
33
|
+
bgBlue: isTTY ? '\x1b[44m' : '',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const W = 54; // box width (inner)
|
|
37
|
+
|
|
38
|
+
function repeat(ch, n) { return ch.repeat(Math.max(0, n)); }
|
|
39
|
+
function pad(str, n) {
|
|
40
|
+
const visible = str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
41
|
+
return str + repeat(' ', Math.max(0, n - visible.length));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ─── Banner ───────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
function printBanner() {
|
|
47
|
+
const top = `╔${repeat('═', W)}╗`;
|
|
48
|
+
const bot = `╚${repeat('═', W)}╝`;
|
|
49
|
+
const div = `╟${repeat('─', W)}╢`;
|
|
50
|
+
const empty = `║${repeat(' ', W)}║`;
|
|
51
|
+
|
|
52
|
+
const logoLines = [
|
|
53
|
+
' ██████╗ ██╗ ██╗████████╗ ██████╗',
|
|
54
|
+
' ██╔═══██╗ ██║ ██║╚══██╔══╝██╔═══██╗',
|
|
55
|
+
' ███████║ ██║ ██║ ██║ ██║ ██║',
|
|
56
|
+
' ██╔══██║ ██║ ██║ ██║ ██║ ██║',
|
|
57
|
+
' ██║ ██║ ╚██████╔╝ ██║ ╚██████╔╝',
|
|
58
|
+
' ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ',
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const pkg = require('./package.json');
|
|
62
|
+
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log(c.cyan + c.bold + top + c.reset);
|
|
65
|
+
console.log(c.cyan + c.bold + empty + c.reset);
|
|
66
|
+
|
|
67
|
+
for (const line of logoLines) {
|
|
68
|
+
const inner = pad(c.yellow + c.bold + line + c.reset, W + (c.yellow + c.bold + c.reset).length * 2);
|
|
69
|
+
console.log(c.cyan + c.bold + '║' + c.reset + inner + c.cyan + c.bold + '║' + c.reset);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Pilot subtitle
|
|
73
|
+
const subtitle = '⚡ A N T I G R A V I T Y A U T O P I L O T ⚡';
|
|
74
|
+
const subInner = pad(c.white + c.bold + subtitle.padStart(Math.floor((W + subtitle.length) / 2)).padEnd(W) + c.reset,
|
|
75
|
+
W + (c.white + c.bold + c.reset).length * 2);
|
|
76
|
+
console.log(c.cyan + c.bold + '║' + c.reset + c.cyan + c.bold + empty.slice(1, -1) + c.reset + c.cyan + c.bold + '║' + c.reset);
|
|
77
|
+
console.log(c.cyan + c.bold + '║' + c.reset + subInner + c.cyan + c.bold + '║' + c.reset);
|
|
78
|
+
|
|
79
|
+
// Version line
|
|
80
|
+
const ver = `v${pkg.version} · MIT License · github.com/nguyenhx2/Antigravity-AutoPilot`;
|
|
81
|
+
const verInner = pad(c.gray + ver.padStart(Math.floor((W + ver.length) / 2)).padEnd(W) + c.reset,
|
|
82
|
+
W + (c.gray + c.reset).length * 2);
|
|
83
|
+
console.log(c.cyan + c.bold + '║' + c.reset + verInner + c.cyan + c.bold + '║' + c.reset);
|
|
84
|
+
|
|
85
|
+
console.log(c.cyan + c.bold + empty + c.reset);
|
|
86
|
+
console.log(c.cyan + c.bold + bot + c.reset);
|
|
87
|
+
console.log('');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── Help Screen ──────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
function printHelp() {
|
|
93
|
+
const cmds = [
|
|
94
|
+
['(no args)', 'Apply the AutoPilot patch'],
|
|
95
|
+
['--check', 'Check current patch status'],
|
|
96
|
+
['--revert', 'Restore original files'],
|
|
97
|
+
['--help', 'Show this help screen'],
|
|
98
|
+
];
|
|
99
|
+
console.log(c.bold + c.white + ' USAGE' + c.reset);
|
|
100
|
+
console.log(c.gray + ' ─────────────────────────────────────────────' + c.reset);
|
|
101
|
+
console.log(' ' + c.cyan + 'npx antigravity-autopilot' + c.reset + c.gray + ' [option]' + c.reset + '\n');
|
|
102
|
+
console.log(c.bold + c.white + ' OPTIONS' + c.reset);
|
|
103
|
+
console.log(c.gray + ' ─────────────────────────────────────────────' + c.reset);
|
|
104
|
+
for (const [flag, desc] of cmds) {
|
|
105
|
+
console.log(' ' + c.yellow + c.bold + flag.padEnd(12) + c.reset + ' ' + c.white + desc + c.reset);
|
|
106
|
+
}
|
|
107
|
+
console.log('');
|
|
108
|
+
console.log(c.bold + c.white + ' WORKFLOW' + c.reset);
|
|
109
|
+
console.log(c.gray + ' ─────────────────────────────────────────────' + c.reset);
|
|
110
|
+
console.log(' ' + c.green + '1.' + c.reset + ' Run ' + c.cyan + 'npx antigravity-autopilot' + c.reset + ' → patch applied');
|
|
111
|
+
console.log(' ' + c.green + '2.' + c.reset + ' Restart Antigravity → AutoPilot active 🚀');
|
|
112
|
+
console.log(' ' + c.green + '3.' + c.reset + ' Run ' + c.cyan + '--revert' + c.reset + ' → undo anytime');
|
|
113
|
+
console.log('');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── Section header ───────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
function section(title, icon) {
|
|
119
|
+
const line = `${icon} ${title}`;
|
|
120
|
+
console.log(c.bold + c.white + line + c.reset);
|
|
121
|
+
console.log(c.gray + ' ' + repeat('─', W - 2) + c.reset);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ─── Installation Detection ───────────────────────────────────────────────────
|
|
23
125
|
|
|
24
126
|
function findAntigravityPath() {
|
|
25
127
|
const candidates = [];
|
|
@@ -62,47 +164,36 @@ function getVersion(basePath) {
|
|
|
62
164
|
} catch { return 'unknown'; }
|
|
63
165
|
}
|
|
64
166
|
|
|
65
|
-
// ─── Core Patch Logic
|
|
167
|
+
// ─── Core Patch Logic ─────────────────────────────────────────────────────────
|
|
66
168
|
|
|
67
169
|
function analyzeFile(content, label) {
|
|
68
|
-
|
|
69
|
-
const onChangeRe = /(\w+)=(\w+)\((\w+)=>\{\w+\?\.setTerminalAutoExecutionPolicy\?\.\(\3\),\3===(\w+)\.EAGER&&(\w+)\(!0\)\},\[[\w,]*\]\)/;
|
|
170
|
+
const onChangeRe = /(\w+)=(\w+)\((\w+)=>\{\w+\?\.setTerminalAutoExecutionPolicy\?\.\(\3\),\3===(\w+)\.EAGER\&\&(\w+)\(!0\)\},\[[\w,]*\]\)/;
|
|
70
171
|
const onChangeMatch = content.match(onChangeRe);
|
|
71
|
-
if (!onChangeMatch) {
|
|
72
|
-
console.log(` ❌ [${label}] Could not find onChange handler pattern`);
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
172
|
+
if (!onChangeMatch) { return null; }
|
|
75
173
|
|
|
76
174
|
const [fullMatch, , callbackAlias, , enumAlias, confirmFn] = onChangeMatch;
|
|
77
175
|
const matchIndex = content.indexOf(fullMatch);
|
|
78
|
-
console.log(` 📋 [${label}] Found onChange at offset ${matchIndex}`);
|
|
79
|
-
console.log(` callback=${callbackAlias}, enum=${enumAlias}, confirm=${confirmFn}`);
|
|
80
176
|
|
|
81
|
-
|
|
82
|
-
const policyRe = new RegExp(`(\\w+)=\\w+\\?\\.terminalAutoExecutionPolicy\\?\\?${enumAlias}\\.OFF`);
|
|
177
|
+
const policyRe = new RegExp(`(\\w+)=\\w+\\.terminalAutoExecutionPolicy\\?\\?${enumAlias}\\.OFF`);
|
|
83
178
|
const policyMatch = content.substring(Math.max(0, matchIndex - 2000), matchIndex).match(policyRe);
|
|
84
|
-
if (!policyMatch)
|
|
179
|
+
if (!policyMatch) return null;
|
|
85
180
|
const policyVar = policyMatch[1];
|
|
86
|
-
console.log(` policyVar=${policyVar}`);
|
|
87
181
|
|
|
88
|
-
// 3. Find secureMode variable: VAR=HANDLER?.secureModeEnabled??!1
|
|
89
182
|
const secureRe = /(\w+)=\w+\?\.secureModeEnabled\?\?!1/;
|
|
90
183
|
const secureMatch = content.substring(Math.max(0, matchIndex - 2000), matchIndex).match(secureRe);
|
|
91
|
-
if (!secureMatch)
|
|
184
|
+
if (!secureMatch) return null;
|
|
92
185
|
const secureVar = secureMatch[1];
|
|
93
|
-
console.log(` secureVar=${secureVar}`);
|
|
94
186
|
|
|
95
|
-
// 4. Find useEffect alias via frequency counting
|
|
96
187
|
const nearbyCode = content.substring(Math.max(0, matchIndex - 5000), matchIndex + 5000);
|
|
97
188
|
const effectCandidates = {};
|
|
98
|
-
const effectRe = /\b(\w{2,3})\(
|
|
189
|
+
const effectRe = /\b(\w{2,3})\(()=>\{[^}]{3,80}\},\[/g;
|
|
99
190
|
let m;
|
|
100
191
|
while ((m = effectRe.exec(nearbyCode)) !== null) {
|
|
101
192
|
const alias = m[1];
|
|
102
193
|
if (alias !== callbackAlias && alias !== 'var' && alias !== 'new')
|
|
103
194
|
effectCandidates[alias] = (effectCandidates[alias] || 0) + 1;
|
|
104
195
|
}
|
|
105
|
-
const cleanupRe = /\b(\w{2,3})\(
|
|
196
|
+
const cleanupRe = /\b(\w{2,3})\(()=>\{[^}]*return\s*()=>/g;
|
|
106
197
|
while ((m = cleanupRe.exec(content)) !== null) {
|
|
107
198
|
const alias = m[1];
|
|
108
199
|
if (alias !== callbackAlias)
|
|
@@ -113,10 +204,8 @@ function analyzeFile(content, label) {
|
|
|
113
204
|
for (const [alias, count] of Object.entries(effectCandidates)) {
|
|
114
205
|
if (count > maxCount) { maxCount = count; useEffectAlias = alias; }
|
|
115
206
|
}
|
|
116
|
-
if (!useEffectAlias)
|
|
117
|
-
console.log(` useEffect=${useEffectAlias} (confidence: ${maxCount} hits)`);
|
|
207
|
+
if (!useEffectAlias) return null;
|
|
118
208
|
|
|
119
|
-
// 5. Build patch
|
|
120
209
|
const patchCode = `_aep=${useEffectAlias}(()=>{${policyVar}===${enumAlias}.EAGER&&!${secureVar}&&${confirmFn}(!0)},[]),`;
|
|
121
210
|
return {
|
|
122
211
|
target: fullMatch,
|
|
@@ -125,107 +214,160 @@ function analyzeFile(content, label) {
|
|
|
125
214
|
};
|
|
126
215
|
}
|
|
127
216
|
|
|
128
|
-
// ─── File Operations
|
|
217
|
+
// ─── File Operations ──────────────────────────────────────────────────────────
|
|
129
218
|
|
|
130
219
|
function isPatched(filePath) {
|
|
131
220
|
if (!fs.existsSync(filePath)) return false;
|
|
132
221
|
const c = fs.readFileSync(filePath, 'utf8');
|
|
133
|
-
return c.includes('_aep=') && /_aep=\w+\(
|
|
222
|
+
return c.includes('_aep=') && /_aep=\w+\(()=>\{[^}]+EAGER/.test(c);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function row(icon, color, label, msg) {
|
|
226
|
+
console.log(' ' + color + icon + c.reset + ' ' + c.bold + label.padEnd(14) + c.reset + c.gray + msg + c.reset);
|
|
134
227
|
}
|
|
135
228
|
|
|
136
229
|
function patchFile(filePath, label) {
|
|
137
230
|
if (!fs.existsSync(filePath)) {
|
|
138
|
-
|
|
231
|
+
row('⊘', c.gray, `[${label}]`, 'File not found — skipping');
|
|
139
232
|
return true;
|
|
140
233
|
}
|
|
141
234
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
142
235
|
if (isPatched(filePath)) {
|
|
143
|
-
|
|
236
|
+
row('✔', c.green, `[${label}]`, 'Already patched');
|
|
144
237
|
return true;
|
|
145
238
|
}
|
|
146
239
|
const analysis = analyzeFile(content, label);
|
|
147
|
-
if (!analysis)
|
|
240
|
+
if (!analysis) {
|
|
241
|
+
row('✖', c.red, `[${label}]`, 'Pattern not found — may be incompatible version');
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
148
244
|
|
|
149
245
|
const count = content.split(analysis.target).length - 1;
|
|
150
|
-
if (count !== 1) {
|
|
246
|
+
if (count !== 1) {
|
|
247
|
+
row('✖', c.red, `[${label}]`, `Target found ${count}× (expected 1)`);
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
151
250
|
|
|
152
251
|
const bak = filePath + '.bak';
|
|
153
|
-
if (!fs.existsSync(bak)) {
|
|
252
|
+
if (!fs.existsSync(bak)) {
|
|
253
|
+
fs.copyFileSync(filePath, bak);
|
|
254
|
+
row('◈', c.blue, `[${label}]`, 'Backup created (.bak)');
|
|
255
|
+
}
|
|
154
256
|
|
|
155
257
|
fs.writeFileSync(filePath, content.replace(analysis.target, analysis.replacement), 'utf8');
|
|
156
258
|
const diff = fs.statSync(filePath).size - fs.statSync(bak).size;
|
|
157
|
-
|
|
259
|
+
row('✔', c.green, `[${label}]`, `Patched successfully (+${diff} bytes)`);
|
|
158
260
|
return true;
|
|
159
261
|
}
|
|
160
262
|
|
|
161
263
|
function revertFile(filePath, label) {
|
|
162
264
|
const bak = filePath + '.bak';
|
|
163
|
-
if (!fs.existsSync(bak)) {
|
|
265
|
+
if (!fs.existsSync(bak)) {
|
|
266
|
+
row('⊘', c.gray, `[${label}]`, 'No backup found — skipping');
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
164
269
|
fs.copyFileSync(bak, filePath);
|
|
165
|
-
|
|
270
|
+
row('✔', c.green, `[${label}]`, 'Restored from backup');
|
|
166
271
|
}
|
|
167
272
|
|
|
168
273
|
function checkFile(filePath, label) {
|
|
169
|
-
if (!fs.existsSync(filePath)) {
|
|
274
|
+
if (!fs.existsSync(filePath)) {
|
|
275
|
+
row('✖', c.red, `[${label}]`, 'File not found');
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
170
278
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
171
279
|
const patched = isPatched(filePath);
|
|
172
280
|
const hasBak = fs.existsSync(filePath + '.bak');
|
|
281
|
+
const analysis = !patched ? analyzeFile(content, label) : null;
|
|
282
|
+
|
|
173
283
|
if (patched) {
|
|
174
|
-
|
|
284
|
+
row('✔', c.green, `[${label}]`, 'PATCHED' + (hasBak ? ' · backup exists' : ''));
|
|
285
|
+
} else if (analysis) {
|
|
286
|
+
row('○', c.yellow, `[${label}]`, 'NOT PATCHED · patchable, ready to apply');
|
|
175
287
|
} else {
|
|
176
|
-
|
|
177
|
-
console.log(analysis ? ` ⬜ [${label}] NOT PATCHED (patchable)` : ` ⚠️ [${label}] NOT PATCHED (may be incompatible)`);
|
|
288
|
+
row('⚠', c.yellow, `[${label}]`, 'NOT PATCHED · may be incompatible');
|
|
178
289
|
}
|
|
179
290
|
return patched;
|
|
180
291
|
}
|
|
181
292
|
|
|
182
|
-
// ─── Main
|
|
293
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
183
294
|
|
|
184
295
|
function main() {
|
|
185
296
|
const args = process.argv.slice(2);
|
|
186
|
-
const action = args.includes('--revert') ? 'revert'
|
|
297
|
+
const action = args.includes('--revert') ? 'revert'
|
|
298
|
+
: args.includes('--check') ? 'check'
|
|
299
|
+
: args.includes('--help') ? 'help'
|
|
300
|
+
: 'apply';
|
|
187
301
|
|
|
188
|
-
|
|
189
|
-
console.log('╔══════════════════════════════════════════╗');
|
|
190
|
-
console.log('║ ⚡ Antigravity AutoPilot ║');
|
|
191
|
-
console.log('╚══════════════════════════════════════════╝');
|
|
302
|
+
printBanner();
|
|
192
303
|
|
|
304
|
+
if (action === 'help') { printHelp(); return; }
|
|
305
|
+
|
|
306
|
+
// ── Locate Antigravity ──
|
|
193
307
|
const basePath = findAntigravityPath();
|
|
308
|
+
|
|
309
|
+
console.log(' ' + c.gray + '📍 Installation' + c.reset);
|
|
194
310
|
if (!basePath) {
|
|
195
|
-
console.log('
|
|
311
|
+
console.log(' ' + c.red + c.bold + '✖ Antigravity not found.' + c.reset);
|
|
312
|
+
console.log(' Install Antigravity from ' + c.cyan + 'https://antigravity.dev' + c.reset + ' first.\n');
|
|
196
313
|
process.exit(1);
|
|
197
314
|
}
|
|
198
|
-
|
|
199
|
-
console.log(
|
|
200
|
-
console.log(
|
|
315
|
+
console.log(' ' + c.white + basePath + c.reset);
|
|
316
|
+
console.log(' ' + c.gray + `Version: ${getVersion(basePath)}` + c.reset);
|
|
317
|
+
console.log('');
|
|
201
318
|
|
|
202
319
|
const files = getTargetFiles(basePath);
|
|
203
320
|
|
|
321
|
+
// ── Action ──
|
|
204
322
|
switch (action) {
|
|
205
|
-
case 'check':
|
|
206
|
-
|
|
323
|
+
case 'check': {
|
|
324
|
+
section('Status Check', '🔍');
|
|
325
|
+
console.log('');
|
|
207
326
|
files.forEach(f => checkFile(f.filePath, f.label));
|
|
327
|
+
console.log('');
|
|
328
|
+
const allPatched = files.every(f => isPatched(f.filePath));
|
|
329
|
+
if (allPatched) {
|
|
330
|
+
console.log(' ' + c.green + c.bold + '✔ AutoPilot is ACTIVE on this machine.' + c.reset);
|
|
331
|
+
console.log(' ' + c.gray + 'Restart Antigravity for changes to take effect.' + c.reset);
|
|
332
|
+
} else {
|
|
333
|
+
console.log(' ' + c.yellow + ' Run ' + c.cyan + 'npx antigravity-autopilot' + c.yellow + ' to activate AutoPilot.' + c.reset);
|
|
334
|
+
}
|
|
335
|
+
console.log('');
|
|
208
336
|
break;
|
|
337
|
+
}
|
|
209
338
|
|
|
210
|
-
case 'revert':
|
|
211
|
-
|
|
339
|
+
case 'revert': {
|
|
340
|
+
section('Reverting Patch', '↩');
|
|
341
|
+
console.log('');
|
|
212
342
|
files.forEach(f => revertFile(f.filePath, f.label));
|
|
213
|
-
console.log('
|
|
343
|
+
console.log('');
|
|
344
|
+
console.log(' ' + c.green + c.bold + '✔ Restored!' + c.reset + c.white + ' Restart Antigravity to apply changes.' + c.reset);
|
|
345
|
+
console.log('');
|
|
214
346
|
break;
|
|
347
|
+
}
|
|
215
348
|
|
|
216
349
|
case 'apply':
|
|
217
|
-
default:
|
|
218
|
-
|
|
350
|
+
default: {
|
|
351
|
+
section('Applying AutoPilot Patch', '⚡');
|
|
352
|
+
console.log('');
|
|
219
353
|
const ok = files.every(f => patchFile(f.filePath, f.label));
|
|
354
|
+
console.log('');
|
|
220
355
|
if (ok) {
|
|
221
|
-
console.log('
|
|
222
|
-
console.log('
|
|
223
|
-
console.log('
|
|
356
|
+
console.log(' ┌' + repeat('─', W - 2) + '┐');
|
|
357
|
+
console.log(' │' + pad(c.green + c.bold + ' ✔ Patch applied successfully!' + c.reset, W - 2 + (c.green + c.bold + c.reset).length * 2) + '│');
|
|
358
|
+
console.log(' │' + pad(c.white + ' Restart Antigravity to activate AutoPilot.' + c.reset, W - 2 + (c.white + c.reset).length * 2) + '│');
|
|
359
|
+
console.log(' │' + repeat(' ', W - 2) + '│');
|
|
360
|
+
console.log(' │' + pad(c.gray + ' 💡 Run with --revert to undo at any time.' + c.reset, W - 2 + (c.gray + c.reset).length * 2) + '│');
|
|
361
|
+
console.log(' │' + pad(c.gray + ' ⚠ Re-run this command after Antigravity updates.' + c.reset, W - 2 + (c.gray + c.reset).length * 2) + '│');
|
|
362
|
+
console.log(' └' + repeat('─', W - 2) + '┘');
|
|
224
363
|
} else {
|
|
225
|
-
console.log('
|
|
364
|
+
console.log(' ' + c.red + c.bold + '✖ Some files could not be patched.' + c.reset);
|
|
365
|
+
console.log(' ' + c.gray + 'Check output above for details.' + c.reset);
|
|
226
366
|
process.exit(1);
|
|
227
367
|
}
|
|
368
|
+
console.log('');
|
|
228
369
|
break;
|
|
370
|
+
}
|
|
229
371
|
}
|
|
230
372
|
}
|
|
231
373
|
|
package/extension.js
CHANGED
|
@@ -20,75 +20,94 @@ let _cachedStatus = null;
|
|
|
20
20
|
let autoPilotEnabled = true;
|
|
21
21
|
/** @type {vscode.OutputChannel} */
|
|
22
22
|
let outputChannel;
|
|
23
|
+
/** @type {vscode.ExtensionContext} */
|
|
24
|
+
let _ctx;
|
|
23
25
|
|
|
24
26
|
// ─── Dangerous Command Blocking ───────────────────────────────────────────────
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Built-in dangerous command patterns.
|
|
28
30
|
* Covers Linux/macOS/Windows destructive commands.
|
|
29
|
-
* Each entry: { pattern: RegExp, label: string, os: string[] }
|
|
31
|
+
* Each entry: { id: string, pattern: RegExp, label: string, os: string[] }
|
|
30
32
|
*/
|
|
31
33
|
const BUILTIN_DANGEROUS_PATTERNS = [
|
|
32
34
|
// ── Linux / macOS ──
|
|
33
|
-
{ pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|--force\s+).*\/(
|
|
34
|
-
{ pattern: /rm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\/(\s|$)/, label: 'rm -r / (root wipe)', os: ['linux', 'darwin'] },
|
|
35
|
-
{ pattern: /rm\s+-[a-zA-Z]*r[a-zA-Z]*\s+~(\s|$|\/)/, label: 'rm -r ~ (home wipe)', os: ['linux', 'darwin'] },
|
|
36
|
-
{ pattern: /rm\s+.*--no-preserve-root/, label: 'rm --no-preserve-root', os: ['linux', 'darwin'] },
|
|
37
|
-
{ pattern: /:\(\)\s*\{.*:\|:&\s*\};\s*:/, label: 'Fork bomb :(){:|:&};:', os: ['linux', 'darwin'] },
|
|
38
|
-
{ pattern: /mkfs\.(ext[234]|xfs|btrfs|vfat|ntfs)\s+\/dev\/(sd|hd|nvme|vd)/, label: 'mkfs on block device', os: ['linux', 'darwin'] },
|
|
39
|
-
{ pattern: /dd\s+.*of=\/dev\/(sd[a-z]|hd[a-z]|nvme\d+|zero|null)/, label: 'dd overwrite device', os: ['linux', 'darwin'] },
|
|
40
|
-
{ pattern: />\s*\/dev\/(sd[a-z]|hd[a-z]|nvme\d+)/, label: 'Redirect to block device', os: ['linux', 'darwin'] },
|
|
41
|
-
{ pattern: /shred\s+(-[a-zA-Z]*n\s*\d+\s+)?\/dev\//, label: 'shred device', os: ['linux', 'darwin'] },
|
|
42
|
-
{ pattern: /mv\s+.*\s+\/dev\/null/, label: 'mv to /dev/null', os: ['linux', 'darwin'] },
|
|
43
|
-
{ pattern: /chmod\s+-[rR]\s+000\s+\//, label: 'chmod 000 recursive on /', os: ['linux', 'darwin'] },
|
|
44
|
-
{ pattern: /chmod\s+777\s+-R\s+\/(\s|$)/, label: 'chmod 777 -R /', os: ['linux', 'darwin'] },
|
|
45
|
-
{ pattern: /chown\s+.*-R\s+.*\s+\/(\s|$)/, label: 'chown -R on /', os: ['linux', 'darwin'] },
|
|
46
|
-
{ pattern: /passwd\s+root\s*$/, label: 'passwd root
|
|
47
|
-
{ pattern: /sudo\s+rm\s+-[a-zA-Z]*rf?\s+\/(\s|$)/, label: 'sudo rm -rf /', os: ['linux', 'darwin'] },
|
|
48
|
-
{ pattern: /wget\s+.*\|\s*(ba)?sh/, label: 'wget pipe to shell', os: ['linux', 'darwin'] },
|
|
49
|
-
{ pattern: /curl\s+.*\|\s*(ba)?sh/, label: 'curl pipe to shell', os: ['linux', 'darwin'] },
|
|
50
|
-
{ pattern: /base64\s+-d.*\|\s*(ba)?sh/, label: 'base64 decode pipe to shell', os: ['linux', 'darwin'] },
|
|
51
|
-
{ pattern: /eval\s+\$\(.*\)/, label: 'eval $(...) subshell', os: ['linux', 'darwin'] },
|
|
52
|
-
{ pattern: /fdisk\s+\/dev\/(sd[a-z]|nvme\d+)/, label: 'fdisk on disk', os: ['linux', 'darwin'] },
|
|
53
|
-
{ pattern: /parted\s+\/dev\/(sd[a-z]|nvme\d+)/, label: 'parted on disk', os: ['linux', 'darwin'] },
|
|
54
|
-
{ pattern: /wipefs\s+.*\/dev\//, label: 'wipefs on device', os: ['linux', 'darwin'] },
|
|
55
|
-
{ pattern: /truncate\s+-s\s+0\s+\/dev\//, label: 'truncate device to 0', os: ['linux', 'darwin'] },
|
|
56
|
-
{ pattern: /echo\s+.*>\s*\/boot\//, label: 'overwrite /boot/', os: ['linux', 'darwin'] },
|
|
57
|
-
{ pattern: /cat\s+\/dev\/zero\s+>\s+\//, label: 'cat /dev/zero to /', os: ['linux', 'darwin'] },
|
|
58
|
-
{ pattern: /umount\s+-a/, label: 'umount -a (unmount all)', os: ['linux', 'darwin'] },
|
|
59
|
-
{ pattern: /init\s+0/, label: 'init 0 (halt system)', os: ['linux', 'darwin'] },
|
|
60
|
-
{ pattern: /poweroff|halt\s*$/, label: 'System shutdown command', os: ['linux', 'darwin'] },
|
|
61
|
-
{ pattern: /iptables\s+-F/, label: 'iptables -F (flush all rules)', os: ['linux', 'darwin'] },
|
|
62
|
-
{ pattern: /ufw\s+--force\s+reset/, label: 'ufw --force reset', os: ['linux', 'darwin'] },
|
|
35
|
+
{ id: 'rm-rf-root', pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|--force\s+).*\/(\\s|$)/, label: 'rm -rf /', os: ['linux', 'darwin'] },
|
|
36
|
+
{ id: 'rm-r-root', pattern: /rm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\/(\s|$)/, label: 'rm -r / (root wipe)', os: ['linux', 'darwin'] },
|
|
37
|
+
{ id: 'rm-r-home', pattern: /rm\s+-[a-zA-Z]*r[a-zA-Z]*\s+~(\s|$|\/)/, label: 'rm -r ~ (home wipe)', os: ['linux', 'darwin'] },
|
|
38
|
+
{ id: 'rm-no-preserve', pattern: /rm\s+.*--no-preserve-root/, label: 'rm --no-preserve-root', os: ['linux', 'darwin'] },
|
|
39
|
+
{ id: 'fork-bomb', pattern: /:\(\)\s*\{.*:\|:&\s*\};\s*:/, label: 'Fork bomb :(){:|:&};:', os: ['linux', 'darwin'] },
|
|
40
|
+
{ id: 'mkfs-device', pattern: /mkfs\.(ext[234]|xfs|btrfs|vfat|ntfs)\s+\/dev\/(sd|hd|nvme|vd)/, label: 'mkfs on block device', os: ['linux', 'darwin'] },
|
|
41
|
+
{ id: 'dd-overwrite', pattern: /dd\s+.*of=\/dev\/(sd[a-z]|hd[a-z]|nvme\d+|zero|null)/, label: 'dd overwrite device', os: ['linux', 'darwin'] },
|
|
42
|
+
{ id: 'redirect-block', pattern: />\s*\/dev\/(sd[a-z]|hd[a-z]|nvme\d+)/, label: 'Redirect to block device', os: ['linux', 'darwin'] },
|
|
43
|
+
{ id: 'shred-device', pattern: /shred\s+(-[a-zA-Z]*n\s*\d+\s+)?\/dev\//, label: 'shred device', os: ['linux', 'darwin'] },
|
|
44
|
+
{ id: 'mv-devnull', pattern: /mv\s+.*\s+\/dev\/null/, label: 'mv to /dev/null', os: ['linux', 'darwin'] },
|
|
45
|
+
{ id: 'chmod-000', pattern: /chmod\s+-[rR]\s+000\s+\//, label: 'chmod 000 recursive on /', os: ['linux', 'darwin'] },
|
|
46
|
+
{ id: 'chmod-777', pattern: /chmod\s+777\s+-R\s+\/(\s|$)/, label: 'chmod 777 -R /', os: ['linux', 'darwin'] },
|
|
47
|
+
{ id: 'chown-root', pattern: /chown\s+.*-R\s+.*\s+\/(\s|$)/, label: 'chown -R on /', os: ['linux', 'darwin'] },
|
|
48
|
+
{ id: 'passwd-root', pattern: /passwd\s+root\s*$/, label: 'passwd root', os: ['linux', 'darwin'] },
|
|
49
|
+
{ id: 'sudo-rm-rf', pattern: /sudo\s+rm\s+-[a-zA-Z]*rf?\s+\/(\s|$)/, label: 'sudo rm -rf /', os: ['linux', 'darwin'] },
|
|
50
|
+
{ id: 'wget-pipe-sh', pattern: /wget\s+.*\|\s*(ba)?sh/, label: 'wget pipe to shell', os: ['linux', 'darwin'] },
|
|
51
|
+
{ id: 'curl-pipe-sh', pattern: /curl\s+.*\|\s*(ba)?sh/, label: 'curl pipe to shell', os: ['linux', 'darwin'] },
|
|
52
|
+
{ id: 'base64-pipe-sh', pattern: /base64\s+-d.*\|\s*(ba)?sh/, label: 'base64 decode pipe to shell', os: ['linux', 'darwin'] },
|
|
53
|
+
{ id: 'eval-subshell', pattern: /eval\s+\$\(.*\)/, label: 'eval $(...) subshell', os: ['linux', 'darwin'] },
|
|
54
|
+
{ id: 'fdisk-disk', pattern: /fdisk\s+\/dev\/(sd[a-z]|nvme\d+)/, label: 'fdisk on disk', os: ['linux', 'darwin'] },
|
|
55
|
+
{ id: 'parted-disk', pattern: /parted\s+\/dev\/(sd[a-z]|nvme\d+)/, label: 'parted on disk', os: ['linux', 'darwin'] },
|
|
56
|
+
{ id: 'wipefs-dev', pattern: /wipefs\s+.*\/dev\//, label: 'wipefs on device', os: ['linux', 'darwin'] },
|
|
57
|
+
{ id: 'truncate-dev', pattern: /truncate\s+-s\s+0\s+\/dev\//, label: 'truncate device to 0', os: ['linux', 'darwin'] },
|
|
58
|
+
{ id: 'echo-boot', pattern: /echo\s+.*>\s*\/boot\//, label: 'overwrite /boot/', os: ['linux', 'darwin'] },
|
|
59
|
+
{ id: 'cat-devzero', pattern: /cat\s+\/dev\/zero\s+>\s+\//, label: 'cat /dev/zero to /', os: ['linux', 'darwin'] },
|
|
60
|
+
{ id: 'umount-all', pattern: /umount\s+-a/, label: 'umount -a (unmount all)', os: ['linux', 'darwin'] },
|
|
61
|
+
{ id: 'init-0', pattern: /init\s+0/, label: 'init 0 (halt system)', os: ['linux', 'darwin'] },
|
|
62
|
+
{ id: 'poweroff', pattern: /poweroff|halt\s*$/, label: 'System shutdown command', os: ['linux', 'darwin'] },
|
|
63
|
+
{ id: 'iptables-flush', pattern: /iptables\s+-F/, label: 'iptables -F (flush all rules)', os: ['linux', 'darwin'] },
|
|
64
|
+
{ id: 'ufw-reset', pattern: /ufw\s+--force\s+reset/, label: 'ufw --force reset', os: ['linux', 'darwin'] },
|
|
63
65
|
// ── macOS specific ──
|
|
64
|
-
{ pattern: /diskutil\s+(eraseDisk|eraseVolume|partitionDisk)\s+/, label: 'diskutil erase/repartition', os: ['darwin'] },
|
|
65
|
-
{ pattern: /diskutil\s+zeroDisk\s+/, label: 'diskutil zeroDisk', os: ['darwin'] },
|
|
66
|
-
{ pattern: /csrutil\s+disable/, label: 'csrutil disable (SIP)', os: ['darwin'] },
|
|
66
|
+
{ id: 'diskutil-erase', pattern: /diskutil\s+(eraseDisk|eraseVolume|partitionDisk)\s+/, label: 'diskutil erase/repartition', os: ['darwin'] },
|
|
67
|
+
{ id: 'diskutil-zero', pattern: /diskutil\s+zeroDisk\s+/, label: 'diskutil zeroDisk', os: ['darwin'] },
|
|
68
|
+
{ id: 'csrutil-disable', pattern: /csrutil\s+disable/, label: 'csrutil disable (SIP)', os: ['darwin'] },
|
|
67
69
|
// ── Windows (PowerShell / cmd) ──
|
|
68
|
-
{ pattern: /Format-Volume\s+.*-Confirm:\s*\$false/i, label: 'Format-Volume
|
|
69
|
-
{ pattern: /format\s+[cC]:\s*\/[qQy]/i, label: 'format C: /q or /y', os: ['win32'] },
|
|
70
|
-
{ pattern: /format\s+[a-zA-Z]:\s*\/[qQy]/i, label: 'format <drive> /q or /y', os: ['win32'] },
|
|
71
|
-
{ pattern: /del\s+\/[fsqSFQ]+\s+[cC]:\\/i, label: 'del /f/s/q C:\\ (wipe
|
|
72
|
-
{ pattern: /rd\s+\/[sq]+\s+[cC]:\\/i, label: 'rd /s/q C:\\ (remove all)', os: ['win32'] },
|
|
73
|
-
{ pattern: /Remove-Item\s+.*-Recurse\s+.*-Force.*[cC]:\\/i, label: 'Remove-Item -Recurse
|
|
74
|
-
{ pattern: /Remove-Item\s+.*-Recurse\s+.*-Force\s+\/\s/i, label: 'Remove-Item -Recurse
|
|
75
|
-
{ pattern: /Set-ExecutionPolicy\s+Unrestricted\s+-Force/i, label: '
|
|
76
|
-
{ pattern: /reg\s+(delete|add)\s+HKLM\\SYSTEM\\CurrentControlSet/i, label: 'reg
|
|
77
|
-
{ pattern: /bcdedit\s+\/deletevalue/i, label: 'bcdedit /deletevalue
|
|
78
|
-
{ pattern: /bcdedit\s+\/set.*safeboot/i, label: 'bcdedit
|
|
79
|
-
{ pattern: /cipher\s+\/w:[cC]:\\/i, label: 'cipher /w:C:\\ (wipe
|
|
80
|
-
{ pattern: /sfc\s+\/scannow.*\/offwindir/i, label: 'sfc offline
|
|
81
|
-
{ pattern: /wmic\s+.*delete/i, label: 'wmic delete', os: ['win32'] },
|
|
82
|
-
{ pattern: /Invoke-Expression\s+\(.*Download.*\)/i, label: 'IEX download-and-
|
|
83
|
-
{ pattern: /iex\s+\(.*WebClient.*DownloadString/i, label: 'iex WebClient
|
|
84
|
-
{ pattern: /powershell\s+.*-EncodedCommand/i, label: 'powershell -EncodedCommand
|
|
85
|
-
{ pattern: /net\s+user\s+administrator\s+\*?\s*\/active:yes/i, label: 'net user
|
|
86
|
-
{ pattern: /takeown\s+\/f\s+[cC]:\\/i, label: 'takeown /f C:\\
|
|
87
|
-
{ pattern: /icacls\s+[cC]:\\\s+\/grant/i, label: 'icacls C:\\ /grant
|
|
70
|
+
{ id: 'format-volume', pattern: /Format-Volume\s+.*-Confirm:\s*\$false/i, label: 'Format-Volume no confirm', os: ['win32'] },
|
|
71
|
+
{ id: 'format-c-quick', pattern: /format\s+[cC]:\s*\/[qQy]/i, label: 'format C: /q or /y', os: ['win32'] },
|
|
72
|
+
{ id: 'format-drive', pattern: /format\s+[a-zA-Z]:\s*\/[qQy]/i, label: 'format <drive> /q or /y', os: ['win32'] },
|
|
73
|
+
{ id: 'del-wipe', pattern: /del\s+\/[fsqSFQ]+\s+[cC]:\\/i, label: 'del /f/s/q C:\\ (wipe)', os: ['win32'] },
|
|
74
|
+
{ id: 'rd-all', pattern: /rd\s+\/[sq]+\s+[cC]:\\/i, label: 'rd /s/q C:\\ (remove all)', os: ['win32'] },
|
|
75
|
+
{ id: 'remove-item-c', pattern: /Remove-Item\s+.*-Recurse\s+.*-Force.*[cC]:\\/i, label: 'Remove-Item -Recurse C:\\', os: ['win32'] },
|
|
76
|
+
{ id: 'remove-item-root', pattern: /Remove-Item\s+.*-Recurse\s+.*-Force\s+\/\s/i, label: 'Remove-Item -Recurse /', os: ['win32'] },
|
|
77
|
+
{ id: 'exec-policy', pattern: /Set-ExecutionPolicy\s+Unrestricted\s+-Force/i, label: 'ExecutionPolicy Unrestricted', os: ['win32'] },
|
|
78
|
+
{ id: 'reg-system', pattern: /reg\s+(delete|add)\s+HKLM\\SYSTEM\\CurrentControlSet/i, label: 'reg modify HKLM\\SYSTEM', os: ['win32'] },
|
|
79
|
+
{ id: 'bcdedit-del', pattern: /bcdedit\s+\/deletevalue/i, label: 'bcdedit /deletevalue', os: ['win32'] },
|
|
80
|
+
{ id: 'bcdedit-safe', pattern: /bcdedit\s+\/set.*safeboot/i, label: 'bcdedit safeboot', os: ['win32'] },
|
|
81
|
+
{ id: 'cipher-wipe', pattern: /cipher\s+\/w:[cC]:\\/i, label: 'cipher /w:C:\\ (wipe)', os: ['win32'] },
|
|
82
|
+
{ id: 'sfc-offline', pattern: /sfc\s+\/scannow.*\/offwindir/i, label: 'sfc offline repair', os: ['win32'] },
|
|
83
|
+
{ id: 'wmic-delete', pattern: /wmic\s+.*delete/i, label: 'wmic delete', os: ['win32'] },
|
|
84
|
+
{ id: 'iex-download', pattern: /Invoke-Expression\s+\(.*Download.*\)/i, label: 'IEX download-and-exec', os: ['win32'] },
|
|
85
|
+
{ id: 'iex-webclient', pattern: /iex\s+\(.*WebClient.*DownloadString/i, label: 'iex WebClient (remote exec)', os: ['win32'] },
|
|
86
|
+
{ id: 'ps-encoded', pattern: /powershell\s+.*-EncodedCommand/i, label: 'powershell -EncodedCommand', os: ['win32'] },
|
|
87
|
+
{ id: 'net-admin', pattern: /net\s+user\s+administrator\s+\*?\s*\/active:yes/i, label: 'net user admin enable', os: ['win32'] },
|
|
88
|
+
{ id: 'takeown-c', pattern: /takeown\s+\/f\s+[cC]:\\/i, label: 'takeown /f C:\\', os: ['win32'] },
|
|
89
|
+
{ id: 'icacls-c', pattern: /icacls\s+[cC]:\\\s+\/grant/i, label: 'icacls C:\\ /grant', os: ['win32'] },
|
|
88
90
|
];
|
|
89
91
|
|
|
92
|
+
/** Get the set of removed pattern IDs from global state */
|
|
93
|
+
function getRemovedPatternIds() {
|
|
94
|
+
const raw = _ctx.globalState.get('removedPatternIds', []);
|
|
95
|
+
return new Set(Array.isArray(raw) ? raw : []);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Save a set of removed pattern IDs to global state */
|
|
99
|
+
function saveRemovedPatternIds(ids) {
|
|
100
|
+
_ctx.globalState.update('removedPatternIds', [...ids]);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Get active built-in patterns (not removed by user) */
|
|
104
|
+
function getActiveBuiltinPatterns() {
|
|
105
|
+
const removed = getRemovedPatternIds();
|
|
106
|
+
return BUILTIN_DANGEROUS_PATTERNS.filter(p => !removed.has(p.id));
|
|
107
|
+
}
|
|
108
|
+
|
|
90
109
|
/**
|
|
91
|
-
* Checks a command string against built-in + custom dangerous patterns.
|
|
110
|
+
* Checks a command string against active built-in + custom dangerous patterns.
|
|
92
111
|
* @param {string} cmd
|
|
93
112
|
* @returns {{ matched: boolean, label: string, pattern: string }}
|
|
94
113
|
*/
|
|
@@ -100,8 +119,8 @@ function checkDangerousCommand(cmd) {
|
|
|
100
119
|
const platform = process.platform; // 'win32' | 'linux' | 'darwin'
|
|
101
120
|
const trimmed = cmd.trim();
|
|
102
121
|
|
|
103
|
-
// Check built-in patterns (platform-filtered)
|
|
104
|
-
for (const entry of
|
|
122
|
+
// Check active built-in patterns (platform-filtered, respecting user removals)
|
|
123
|
+
for (const entry of getActiveBuiltinPatterns()) {
|
|
105
124
|
if (!entry.os.includes(platform)) continue;
|
|
106
125
|
if (entry.pattern.test(trimmed)) {
|
|
107
126
|
return { matched: true, label: entry.label, pattern: entry.pattern.toString() };
|
|
@@ -307,7 +326,6 @@ class AntigravityPanelProvider {
|
|
|
307
326
|
} else if (msg.command === 'toggleEnabled') {
|
|
308
327
|
autoPilotEnabled = !autoPilotEnabled;
|
|
309
328
|
updateStatusBarFromCache();
|
|
310
|
-
// Persist into workspace config
|
|
311
329
|
const cfg = vscode.workspace.getConfiguration('antigravityAutoAccept');
|
|
312
330
|
await cfg.update('enabledOnStartup', autoPilotEnabled, vscode.ConfigurationTarget.Global);
|
|
313
331
|
if (panelProvider) panelProvider.sendEnabled(autoPilotEnabled);
|
|
@@ -316,12 +334,37 @@ class AntigravityPanelProvider {
|
|
|
316
334
|
);
|
|
317
335
|
} else if (msg.command === 'openSettings') {
|
|
318
336
|
vscode.commands.executeCommand('workbench.action.openSettings', 'antigravityAutoAccept');
|
|
337
|
+
} else if (msg.command === 'toggleCommandBlocking') {
|
|
338
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoAccept');
|
|
339
|
+
const current = cfg.get('dangerousCommandBlocking.enabled', true);
|
|
340
|
+
const next = !current;
|
|
341
|
+
await cfg.update('dangerousCommandBlocking.enabled', next, vscode.ConfigurationTarget.Global);
|
|
342
|
+
this.sendBlockingEnabled(next);
|
|
343
|
+
vscode.window.showInformationMessage(
|
|
344
|
+
next ? '🛡️ Command Blocking enabled' : '⚠️ Command Blocking disabled',
|
|
345
|
+
);
|
|
346
|
+
} else if (msg.command === 'removePattern') {
|
|
347
|
+
// Remove a built-in pattern by ID
|
|
348
|
+
const removed = getRemovedPatternIds();
|
|
349
|
+
removed.add(msg.id);
|
|
350
|
+
saveRemovedPatternIds(removed);
|
|
351
|
+
this.sendPatterns();
|
|
352
|
+
vscode.window.showInformationMessage(`Removed preset: ${msg.label}`);
|
|
353
|
+
} else if (msg.command === 'resetPatterns') {
|
|
354
|
+
// Reset all removed patterns
|
|
355
|
+
saveRemovedPatternIds(new Set());
|
|
356
|
+
this.sendPatterns();
|
|
357
|
+
vscode.window.showInformationMessage('🔄 All preset dangerous commands restored to defaults.');
|
|
319
358
|
}
|
|
320
359
|
});
|
|
321
360
|
|
|
322
361
|
// Initial load
|
|
323
362
|
refreshStatus();
|
|
324
363
|
this.sendEnabled(autoPilotEnabled);
|
|
364
|
+
this.sendBlockingEnabled(
|
|
365
|
+
vscode.workspace.getConfiguration('antigravityAutoAccept').get('dangerousCommandBlocking.enabled', true),
|
|
366
|
+
);
|
|
367
|
+
this.sendPatterns();
|
|
325
368
|
}
|
|
326
369
|
|
|
327
370
|
/** @param {string} text */
|
|
@@ -346,6 +389,25 @@ class AntigravityPanelProvider {
|
|
|
346
389
|
this._view.webview.postMessage({ command: 'setEnabled', enabled });
|
|
347
390
|
}
|
|
348
391
|
|
|
392
|
+
/** @param {boolean} enabled */
|
|
393
|
+
sendBlockingEnabled(enabled) {
|
|
394
|
+
if (!this._view) return;
|
|
395
|
+
this._view.webview.postMessage({ command: 'setBlockingEnabled', enabled });
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** Send current pattern list to the webview */
|
|
399
|
+
sendPatterns() {
|
|
400
|
+
if (!this._view) return;
|
|
401
|
+
const removed = getRemovedPatternIds();
|
|
402
|
+
const patterns = BUILTIN_DANGEROUS_PATTERNS.map(p => ({
|
|
403
|
+
id: p.id,
|
|
404
|
+
label: p.label,
|
|
405
|
+
os: p.os,
|
|
406
|
+
active: !removed.has(p.id),
|
|
407
|
+
}));
|
|
408
|
+
this._view.webview.postMessage({ command: 'patterns', patterns, totalBuiltin: BUILTIN_DANGEROUS_PATTERNS.length });
|
|
409
|
+
}
|
|
410
|
+
|
|
349
411
|
_getHtml() {
|
|
350
412
|
return /* html */`<!DOCTYPE html>
|
|
351
413
|
<html lang="en">
|
|
@@ -431,20 +493,57 @@ class AntigravityPanelProvider {
|
|
|
431
493
|
background:var(--vscode-editor-background);
|
|
432
494
|
font-size:11px;font-weight:600;
|
|
433
495
|
border-bottom:1px solid var(--vscode-panel-border);
|
|
496
|
+
cursor:pointer;
|
|
434
497
|
}
|
|
498
|
+
.section-header:hover{opacity:.85}
|
|
435
499
|
.section-header .badge{
|
|
436
500
|
font-size:9px;padding:1px 6px;border-radius:10px;
|
|
437
|
-
background:#
|
|
501
|
+
background:#4ec94e;color:#fff;font-weight:700;
|
|
438
502
|
}
|
|
439
|
-
.section-header .badge.
|
|
440
|
-
|
|
441
|
-
.
|
|
442
|
-
|
|
443
|
-
|
|
503
|
+
.section-header .badge.off{background:#e06c75}
|
|
504
|
+
|
|
505
|
+
.pattern-list{
|
|
506
|
+
max-height:220px;overflow-y:auto;padding:4px 0;
|
|
507
|
+
}
|
|
508
|
+
.pattern-list::-webkit-scrollbar{width:4px}
|
|
509
|
+
.pattern-list::-webkit-scrollbar-thumb{background:#555;border-radius:2px}
|
|
510
|
+
|
|
511
|
+
.pattern-item{
|
|
512
|
+
display:flex;align-items:center;gap:6px;
|
|
513
|
+
font-size:10px;padding:3px 10px;
|
|
514
|
+
color:var(--vscode-foreground);
|
|
515
|
+
border-bottom:1px solid rgba(128,128,128,.1);
|
|
516
|
+
transition:background .15s;
|
|
517
|
+
}
|
|
518
|
+
.pattern-item:hover{background:rgba(128,128,128,.1)}
|
|
519
|
+
.pattern-item.removed{opacity:.35;text-decoration:line-through}
|
|
520
|
+
.pattern-os{
|
|
521
|
+
font-size:8px;padding:1px 4px;border-radius:3px;
|
|
522
|
+
background:rgba(128,128,128,.2);color:var(--vscode-descriptionForeground);
|
|
523
|
+
flex-shrink:0;
|
|
524
|
+
}
|
|
525
|
+
.pattern-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
526
|
+
.pattern-del{
|
|
527
|
+
cursor:pointer;color:#e06c75;font-size:12px;flex-shrink:0;
|
|
528
|
+
opacity:0;transition:opacity .15s;line-height:1;
|
|
529
|
+
background:none;border:none;padding:0 2px;font-family:inherit;
|
|
530
|
+
}
|
|
531
|
+
.pattern-item:hover .pattern-del{opacity:1}
|
|
532
|
+
.pattern-del:hover{color:#ff4444}
|
|
533
|
+
|
|
534
|
+
.pattern-footer{
|
|
535
|
+
display:flex;align-items:center;justify-content:space-between;
|
|
536
|
+
padding:5px 10px;font-size:9px;
|
|
537
|
+
color:var(--vscode-descriptionForeground);
|
|
538
|
+
border-top:1px solid var(--vscode-panel-border);
|
|
539
|
+
background:var(--vscode-editor-background);
|
|
444
540
|
}
|
|
445
|
-
.
|
|
446
|
-
|
|
541
|
+
.pattern-reset{
|
|
542
|
+
cursor:pointer;color:var(--vscode-textLink-foreground);
|
|
543
|
+
background:none;border:none;font-size:9px;padding:0;
|
|
544
|
+
font-family:inherit;
|
|
447
545
|
}
|
|
546
|
+
.pattern-reset:hover{text-decoration:underline}
|
|
448
547
|
|
|
449
548
|
/* ── Path box ── */
|
|
450
549
|
.path-box{
|
|
@@ -481,6 +580,10 @@ class AntigravityPanelProvider {
|
|
|
481
580
|
color:var(--vscode-descriptionForeground);
|
|
482
581
|
text-align:center;line-height:1.5;
|
|
483
582
|
}
|
|
583
|
+
.collapsed .pattern-list{display:none}
|
|
584
|
+
.collapsed .pattern-footer{display:none}
|
|
585
|
+
.chevron{transition:transform .2s;display:inline-block}
|
|
586
|
+
.collapsed .chevron{transform:rotate(-90deg)}
|
|
484
587
|
</style>
|
|
485
588
|
</head>
|
|
486
589
|
<body>
|
|
@@ -518,20 +621,30 @@ class AntigravityPanelProvider {
|
|
|
518
621
|
|
|
519
622
|
<div class="path-box" id="pathBox" style="display:none"></div>
|
|
520
623
|
|
|
624
|
+
<!-- Command Blocking toggle -->
|
|
625
|
+
<div class="toggle-row" id="blockingToggleRow">
|
|
626
|
+
<div>
|
|
627
|
+
<div class="toggle-label">🛡️ Command Blocking</div>
|
|
628
|
+
<div class="toggle-sub" id="blockingToggleSub">Active — blocking dangerous commands</div>
|
|
629
|
+
</div>
|
|
630
|
+
<label class="switch" title="Toggle Command Blocking on/off">
|
|
631
|
+
<input type="checkbox" id="blockingToggleCheck" checked onchange="send('toggleCommandBlocking')">
|
|
632
|
+
<span class="slider"></span>
|
|
633
|
+
</label>
|
|
634
|
+
</div>
|
|
635
|
+
|
|
521
636
|
<!-- Dangerous Command Blocking section -->
|
|
522
|
-
<div class="section">
|
|
523
|
-
<div class="section-header">
|
|
524
|
-
🛡️ Command
|
|
525
|
-
<span class="badge
|
|
637
|
+
<div class="section" id="blockSection">
|
|
638
|
+
<div class="section-header" id="blockHeader">
|
|
639
|
+
<span><span class="chevron">▾</span> 🛡️ Dangerous Command Presets</span>
|
|
640
|
+
<span class="badge" id="blockBadge">0 active</span>
|
|
641
|
+
</div>
|
|
642
|
+
<div class="pattern-list" id="patternList">
|
|
643
|
+
<!-- populated dynamically -->
|
|
526
644
|
</div>
|
|
527
|
-
<div class="
|
|
528
|
-
<
|
|
529
|
-
<
|
|
530
|
-
<div class="block-item"><span class="block-dot"></span>format C: / Remove-Item -Force (Windows)</div>
|
|
531
|
-
<div class="block-item"><span class="block-dot"></span>curl/wget pipe to shell</div>
|
|
532
|
-
<div class="block-item"><span class="block-dot"></span>Fork bombs, IEX download-exec</div>
|
|
533
|
-
<div class="block-item"><span class="block-dot"></span>diskutil erase, bcdedit delete</div>
|
|
534
|
-
<div class="block-item" style="color:var(--vscode-foreground);font-style:italic">+ 40 more built-in patterns</div>
|
|
645
|
+
<div class="pattern-footer">
|
|
646
|
+
<span id="patternCount">0 / 0 active</span>
|
|
647
|
+
<button class="pattern-reset" id="resetBtn" title="Restore all removed presets">🔄 Reset Defaults</button>
|
|
535
648
|
</div>
|
|
536
649
|
</div>
|
|
537
650
|
|
|
@@ -545,12 +658,13 @@ class AntigravityPanelProvider {
|
|
|
545
658
|
<script>
|
|
546
659
|
const vscode = acquireVsCodeApi();
|
|
547
660
|
|
|
548
|
-
function send(cmd) {
|
|
549
|
-
if (cmd !== 'openSettings' && cmd !== 'toggleEnabled' && cmd !== '
|
|
661
|
+
function send(cmd, extra) {
|
|
662
|
+
if (cmd !== 'openSettings' && cmd !== 'toggleEnabled' && cmd !== 'toggleCommandBlocking'
|
|
663
|
+
&& cmd !== 'refresh' && cmd !== 'removePattern' && cmd !== 'resetPatterns') {
|
|
550
664
|
document.getElementById('btnApply').disabled = true;
|
|
551
665
|
document.getElementById('btnRevert').disabled = true;
|
|
552
666
|
}
|
|
553
|
-
vscode.postMessage({ command: cmd });
|
|
667
|
+
vscode.postMessage(Object.assign({ command: cmd }, extra || {}));
|
|
554
668
|
}
|
|
555
669
|
|
|
556
670
|
// Wire up buttons
|
|
@@ -561,59 +675,125 @@ class AntigravityPanelProvider {
|
|
|
561
675
|
document.querySelector('.btn-refresh').disabled = true;
|
|
562
676
|
setTimeout(() => { document.querySelector('.btn-refresh').disabled = false; }, 2000);
|
|
563
677
|
});
|
|
678
|
+
document.getElementById('resetBtn').addEventListener('click', () => send('resetPatterns'));
|
|
679
|
+
|
|
680
|
+
// Collapse/expand
|
|
681
|
+
document.getElementById('blockHeader').addEventListener('click', () => {
|
|
682
|
+
document.getElementById('blockSection').classList.toggle('collapsed');
|
|
683
|
+
});
|
|
564
684
|
|
|
565
685
|
send('refresh');
|
|
566
686
|
|
|
687
|
+
/** Render the pattern list */
|
|
688
|
+
function renderPatterns(patterns, totalBuiltin) {
|
|
689
|
+
const list = document.getElementById('patternList');
|
|
690
|
+
list.textContent = '';
|
|
691
|
+
const activeCount = patterns.filter(p => p.active).length;
|
|
692
|
+
document.getElementById('blockBadge').textContent = activeCount + ' active';
|
|
693
|
+
document.getElementById('blockBadge').className = 'badge' + (activeCount === 0 ? ' off' : '');
|
|
694
|
+
document.getElementById('patternCount').textContent = activeCount + ' / ' + totalBuiltin + ' active';
|
|
695
|
+
|
|
696
|
+
const osLabel = { linux: 'LNX', darwin: 'MAC', win32: 'WIN' };
|
|
697
|
+
|
|
698
|
+
for (const p of patterns) {
|
|
699
|
+
const row = document.createElement('div');
|
|
700
|
+
row.className = 'pattern-item' + (p.active ? '' : ' removed');
|
|
701
|
+
|
|
702
|
+
// OS badges
|
|
703
|
+
const osSpan = document.createElement('span');
|
|
704
|
+
osSpan.className = 'pattern-os';
|
|
705
|
+
osSpan.textContent = p.os.map(o => osLabel[o] || o).join('/');
|
|
706
|
+
row.appendChild(osSpan);
|
|
707
|
+
|
|
708
|
+
// Label
|
|
709
|
+
const lbl = document.createElement('span');
|
|
710
|
+
lbl.className = 'pattern-label';
|
|
711
|
+
lbl.textContent = p.label;
|
|
712
|
+
lbl.title = p.label;
|
|
713
|
+
row.appendChild(lbl);
|
|
714
|
+
|
|
715
|
+
// Delete button (only for active items)
|
|
716
|
+
if (p.active) {
|
|
717
|
+
const del = document.createElement('button');
|
|
718
|
+
del.className = 'pattern-del';
|
|
719
|
+
del.textContent = '✕';
|
|
720
|
+
del.title = 'Remove this preset';
|
|
721
|
+
del.addEventListener('click', (e) => {
|
|
722
|
+
e.stopPropagation();
|
|
723
|
+
send('removePattern', { id: p.id, label: p.label });
|
|
724
|
+
});
|
|
725
|
+
row.appendChild(del);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
list.appendChild(row);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
567
732
|
window.addEventListener('message', e => {
|
|
568
|
-
const
|
|
733
|
+
const data = e.data;
|
|
569
734
|
|
|
570
|
-
if (command === 'setEnabled') {
|
|
735
|
+
if (data.command === 'setEnabled') {
|
|
571
736
|
const chk = document.getElementById('toggleCheck');
|
|
572
|
-
chk.checked = enabled;
|
|
573
|
-
document.getElementById('toggleSub').textContent = enabled
|
|
737
|
+
chk.checked = data.enabled;
|
|
738
|
+
document.getElementById('toggleSub').textContent = data.enabled
|
|
574
739
|
? 'Active — executing all commands'
|
|
575
740
|
: 'Suspended — commands require confirmation';
|
|
576
741
|
}
|
|
577
742
|
|
|
578
|
-
if (command === '
|
|
743
|
+
if (data.command === 'setBlockingEnabled') {
|
|
744
|
+
const chk = document.getElementById('blockingToggleCheck');
|
|
745
|
+
chk.checked = data.enabled;
|
|
746
|
+
document.getElementById('blockingToggleSub').textContent = data.enabled
|
|
747
|
+
? 'Active — blocking dangerous commands'
|
|
748
|
+
: 'Disabled — commands not blocked';
|
|
749
|
+
// Dim the presets section when blocking is off
|
|
750
|
+
const section = document.getElementById('blockSection');
|
|
751
|
+
if (section) section.style.opacity = data.enabled ? '1' : '0.4';
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (data.command === 'patterns') {
|
|
755
|
+
renderPatterns(data.patterns, data.totalBuiltin);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (data.command === 'loading') {
|
|
579
759
|
document.getElementById('lbl').className = 'status-label loading';
|
|
580
|
-
document.getElementById('lbl').textContent = text || '⏳ Working...';
|
|
760
|
+
document.getElementById('lbl').textContent = data.text || '⏳ Working...';
|
|
581
761
|
document.getElementById('desc').textContent = 'Please wait...';
|
|
582
762
|
return;
|
|
583
763
|
}
|
|
584
764
|
|
|
585
|
-
if (command !== 'update') return;
|
|
765
|
+
if (data.command !== 'update') return;
|
|
586
766
|
|
|
587
767
|
// Re-enable buttons
|
|
588
768
|
document.getElementById('btnApply').disabled = false;
|
|
589
769
|
document.getElementById('btnRevert').disabled = false;
|
|
590
770
|
|
|
591
|
-
const notFound = !basePath;
|
|
771
|
+
const notFound = !data.basePath;
|
|
592
772
|
|
|
593
|
-
document.getElementById('card').className = 'status-card' + (notFound ? ' not-found' : patched ? ' patched' : '');
|
|
594
|
-
document.getElementById('dot').className = 'dot' + (notFound ? ' not-found' : patched ? ' patched' : '');
|
|
595
|
-
document.getElementById('dot').textContent = notFound ? '✕' : patched ? '✓' : '○';
|
|
773
|
+
document.getElementById('card').className = 'status-card' + (notFound ? ' not-found' : data.patched ? ' patched' : '');
|
|
774
|
+
document.getElementById('dot').className = 'dot' + (notFound ? ' not-found' : data.patched ? ' patched' : '');
|
|
775
|
+
document.getElementById('dot').textContent = notFound ? '✕' : data.patched ? '✓' : '○';
|
|
596
776
|
|
|
597
777
|
const lbl = document.getElementById('lbl');
|
|
598
|
-
lbl.className = 'status-label ' + (notFound ? 'not-found' : patched ? 'patched' : 'pending');
|
|
599
|
-
lbl.textContent = notFound ? 'Not Found' : patched ? 'Patched' : 'Not Patched';
|
|
778
|
+
lbl.className = 'status-label ' + (notFound ? 'not-found' : data.patched ? 'patched' : 'pending');
|
|
779
|
+
lbl.textContent = notFound ? 'Not Found' : data.patched ? 'Patched' : 'Not Patched';
|
|
600
780
|
|
|
601
781
|
document.getElementById('desc').textContent = notFound
|
|
602
782
|
? 'Antigravity installation not detected'
|
|
603
|
-
: patched ? 'AutoPilot is active on this machine' : 'Click APPLY PATCH to activate';
|
|
783
|
+
: data.patched ? 'AutoPilot is active on this machine' : 'Click APPLY PATCH to activate';
|
|
604
784
|
|
|
605
|
-
if (basePath) {
|
|
785
|
+
if (data.basePath) {
|
|
606
786
|
const pb = document.getElementById('pathBox');
|
|
607
|
-
pb.textContent = basePath;
|
|
787
|
+
pb.textContent = data.basePath;
|
|
608
788
|
pb.style.display = 'block';
|
|
609
789
|
}
|
|
610
790
|
|
|
611
|
-
document.getElementById('btnApply').style.display = notFound || patched ? 'none' : 'block';
|
|
612
|
-
document.getElementById('btnRevert').style.display = patched ? 'block' : 'none';
|
|
791
|
+
document.getElementById('btnApply').style.display = notFound || data.patched ? 'none' : 'block';
|
|
792
|
+
document.getElementById('btnRevert').style.display = data.patched ? 'block' : 'none';
|
|
613
793
|
|
|
614
794
|
document.getElementById('noteBox').textContent = notFound
|
|
615
795
|
? 'Install Antigravity first, then click Refresh.'
|
|
616
|
-
: patched ? 'Restart Antigravity to apply changes.' : '';
|
|
796
|
+
: data.patched ? 'Restart Antigravity to apply changes.' : '';
|
|
617
797
|
});
|
|
618
798
|
</script>
|
|
619
799
|
</body>
|
|
@@ -630,6 +810,8 @@ function updateStatusBar() { updateStatusBarFromCache(); }
|
|
|
630
810
|
|
|
631
811
|
/** @param {vscode.ExtensionContext} context */
|
|
632
812
|
function activate(context) {
|
|
813
|
+
_ctx = context;
|
|
814
|
+
|
|
633
815
|
// Shared output channel
|
|
634
816
|
outputChannel = vscode.window.createOutputChannel('AutoPilot');
|
|
635
817
|
context.subscriptions.push(outputChannel);
|
|
@@ -657,9 +839,6 @@ function activate(context) {
|
|
|
657
839
|
);
|
|
658
840
|
|
|
659
841
|
// ── Terminal command watcher (Dangerous Command Blocking) ──────────────────
|
|
660
|
-
// VS Code API: onDidWriteTerminalData captures output; we intercept typed
|
|
661
|
-
// commands via onDidStartTerminalShellExecution (VS Code 1.87+).
|
|
662
|
-
// Fallback: detect via terminal write events.
|
|
663
842
|
if (typeof vscode.window.onDidStartTerminalShellExecution === 'function') {
|
|
664
843
|
context.subscriptions.push(
|
|
665
844
|
vscode.window.onDidStartTerminalShellExecution((event) => {
|
|
@@ -668,14 +847,12 @@ function activate(context) {
|
|
|
668
847
|
const check = checkDangerousCommand(cmd);
|
|
669
848
|
if (check.matched) {
|
|
670
849
|
handleDangerousCommand(cmd, check.label);
|
|
671
|
-
// Note: VS Code does not expose a cancellation API for shell exec;
|
|
672
|
-
// we log/warn/notify. For full blocking, pair with shell hook.
|
|
673
850
|
}
|
|
674
851
|
}),
|
|
675
852
|
);
|
|
676
853
|
}
|
|
677
854
|
|
|
678
|
-
// Config change listener
|
|
855
|
+
// Config change listener
|
|
679
856
|
context.subscriptions.push(
|
|
680
857
|
vscode.workspace.onDidChangeConfiguration((e) => {
|
|
681
858
|
if (e.affectsConfiguration('antigravityAutoAccept.enabledOnStartup')) {
|
package/icon.png
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"name": "antigravity-autopilot",
|
|
3
3
|
"displayName": "Antigravity AutoPilot",
|
|
4
4
|
"description": "Enables autopilot mode for Antigravity: automatically executes all tool calls and terminal commands without manual confirmation. Patches the runtime JS bundle to inject auto-accept logic whenever the 'Always Proceed' policy is active — regex-based and version-agnostic.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.4.0",
|
|
6
|
+
"license": "MIT",
|
|
6
7
|
"publisher": "nguyen-hoang",
|
|
7
8
|
"bin": {
|
|
8
9
|
"antigravity-autopilot": "./cli.js"
|