antigravity-autopilot 1.1.0 → 1.3.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nguyen Hoang (nguyenhx2)
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
@@ -4,6 +4,7 @@
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/antigravity-autopilot)](https://www.npmjs.com/package/antigravity-autopilot)
6
6
  [![GitHub](https://img.shields.io/badge/GitHub-Antigravity--AutoPilot-blue)](https://github.com/nguyenhx2/Antigravity-AutoPilot)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
8
 
8
9
  ---
9
10
 
@@ -17,6 +18,8 @@ Antigravity has an **"Always Proceed"** terminal execution policy, but due to a
17
18
  - ✅ Non-destructive — creates `.bak` backup before patching
18
19
  - ✅ Reversible — restore originals anytime with `--revert`
19
20
  - ✅ Available as VS Code Extension **and** CLI (`npx`)
21
+ - 🛡️ 54+ built-in dangerous command presets (Linux/macOS/Windows)
22
+ - ⚙️ Fully customizable preset management with Reset Defaults
20
23
 
21
24
  ---
22
25
 
@@ -49,7 +52,7 @@ Install the extension directly into Antigravity for a UI-based experience (sideb
49
52
 
50
53
  ```bash
51
54
  # Download .vsix from GitHub Releases, then:
52
- antigravity --install-extension antigravity-autopilot-1.0.0.vsix
55
+ antigravity --install-extension antigravity-autopilot-1.3.0.vsix
53
56
  ```
54
57
 
55
58
  **Extension features:**
@@ -57,6 +60,45 @@ antigravity --install-extension antigravity-autopilot-1.0.0.vsix
57
60
  - 📊 Status bar showing current patch state
58
61
  - ⌨️ Keyboard shortcut: `Ctrl+Shift+F12`
59
62
  - ⚙️ `applyOnStartup` setting for fully automatic operation
63
+ - 🔘 `enabledOnStartup` — toggle AutoPilot active/suspended on launch
64
+
65
+ ---
66
+
67
+ ## 🛡️ Dangerous Command Blocking
68
+
69
+ Built-in protection against destructive commands. **54+ preset patterns** covering all major platforms:
70
+
71
+ | Platform | Examples |
72
+ |----------|----------|
73
+ | **Linux/macOS** | `rm -rf /`, `dd of=/dev/sda`, `mkfs`, fork bombs, `curl \| sh`, `chmod 777 -R /` |
74
+ | **macOS** | `diskutil eraseDisk`, `csrutil disable` |
75
+ | **Windows** | `format C:`, `Remove-Item -Recurse C:\`, `bcdedit /deletevalue`, `IEX download-and-exec` |
76
+
77
+ ### Preset Management (Sidebar UI)
78
+
79
+ - 📋 **View all presets** — full list of blocked commands with OS badges (LNX/MAC/WIN)
80
+ - ✕ **Remove individual presets** — click the ✕ button to exclude a preset
81
+ - 🔄 **Reset Defaults** — restore all removed presets with one click
82
+ - 📊 **Active count** — always see how many presets are active
83
+
84
+ ### Custom Patterns
85
+
86
+ Add your own patterns via Settings:
87
+
88
+ ```json
89
+ "antigravityAutoAccept.dangerousCommandBlocking.customPatterns": [
90
+ "^my-dangerous-script",
91
+ "DROP TABLE"
92
+ ]
93
+ ```
94
+
95
+ ### Action Modes
96
+
97
+ | Mode | Behavior |
98
+ |------|----------|
99
+ | `block` | Block command + show error notification (default) |
100
+ | `warn` | Show warning but allow command to proceed |
101
+ | `log` | Silently log to Output channel |
60
102
 
61
103
  ---
62
104
 
@@ -88,4 +130,4 @@ Variable names are resolved via regex at runtime, making the patch resilient to
88
130
 
89
131
  ## License
90
132
 
91
- MIT
133
+ [MIT](LICENSE)
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 patch status
13
- * npx antigravity-autopilot --revert Restore original files
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
- // ─── Installation Detection ──────────────────────────────────────────────────
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 (regex-based, version-agnostic) ───────────────────────
167
+ // ─── Core Patch Logic ─────────────────────────────────────────────────────────
66
168
 
67
169
  function analyzeFile(content, label) {
68
- // 1. Find the onChange handler for setTerminalAutoExecutionPolicy
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
- // 2. Find policy variable: VAR=HANDLER?.terminalAutoExecutionPolicy??ENUM.OFF
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) { console.log(` ❌ [${label}] Could not find policy variable`); return null; }
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) { console.log(` ❌ [${label}] Could not find secureMode variable`); return null; }
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})\(\(\)=>\{[^}]{3,80}\},\[/g;
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})\(\(\)=>\{[^}]*return\s*\(\)=>/g;
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) { console.log(` ❌ [${label}] Could not determine useEffect alias`); return null; }
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+\(\(\)=>\{[^}]+EAGER/.test(c);
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
- console.log(` ⏭️ [${label}] Not found, skipping`);
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
- console.log(` ⏭️ [${label}] Already patched`);
236
+ row('✔', c.green, `[${label}]`, 'Already patched');
144
237
  return true;
145
238
  }
146
239
  const analysis = analyzeFile(content, label);
147
- if (!analysis) return false;
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) { console.log(` ❌ [${label}] Target found ${count}x (expected 1)`); return false; }
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)) { fs.copyFileSync(filePath, bak); console.log(` 📦 [${label}] Backup created`); }
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
- console.log(`[${label}] Patched (+${diff} bytes)`);
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)) { console.log(` ⏭️ [${label}] No backup, skipping`); return; }
265
+ if (!fs.existsSync(bak)) {
266
+ row('⊘', c.gray, `[${label}]`, 'No backup found — skipping');
267
+ return;
268
+ }
164
269
  fs.copyFileSync(bak, filePath);
165
- console.log(`[${label}] Restored`);
270
+ row('✔', c.green, `[${label}]`, 'Restored from backup');
166
271
  }
167
272
 
168
273
  function checkFile(filePath, label) {
169
- if (!fs.existsSync(filePath)) { console.log(` ❌ [${label}] Not found`); return false; }
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
- console.log(`[${label}] PATCHED` + (hasBak ? ' (backup exists)' : ''));
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
- const analysis = analyzeFile(content, label);
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' : args.includes('--check') ? 'check' : 'apply';
297
+ const action = args.includes('--revert') ? 'revert'
298
+ : args.includes('--check') ? 'check'
299
+ : args.includes('--help') ? 'help'
300
+ : 'apply';
187
301
 
188
- console.log('');
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('\n❌ Antigravity not found. Make sure it is installed.\n');
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(`\n📍 ${basePath}`);
200
- console.log(`📦 Antigravity version: ${getVersion(basePath)}\n`);
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
- console.log('🔍 Checking patch status...\n');
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
- console.log('↩️ Reverting patch...\n');
339
+ case 'revert': {
340
+ section('Reverting Patch', '↩');
341
+ console.log('');
212
342
  files.forEach(f => revertFile(f.filePath, f.label));
213
- console.log('\n✨ Restored! Restart Antigravity to apply changes.');
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
- console.log('🚀 Applying autopilot patch...\n');
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('\n✨ Done! Restart Antigravity to activate AutoPilot.');
222
- console.log('💡 Run with --revert to undo.');
223
- console.log('⚠️ Re-run after Antigravity updates.\n');
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('\n⚠️ Some files could not be patched. Check output above.\n');
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