antigravity-autopilot 1.4.3 → 1.4.5
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/{AutoAccept.ps1 → AutoPilot.ps1} +1 -1
- package/README.md +1 -1
- package/extension.js +94 -17
- package/package.json +22 -12
- package/patcher.js +245 -32
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Antigravity Auto-Accept - Floating Panel
|
|
2
2
|
# A small always-on-top window for toggling auto-accept
|
|
3
|
-
# Run with: powershell -WindowStyle Hidden -File
|
|
3
|
+
# Run with: powershell -WindowStyle Hidden -File AutoPilot.ps1
|
|
4
4
|
|
|
5
5
|
Add-Type -AssemblyName System.Windows.Forms
|
|
6
6
|
Add-Type -AssemblyName System.Drawing
|
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ Built-in protection against destructive commands. **54+ preset patterns** coveri
|
|
|
95
95
|
Add your own patterns via Settings:
|
|
96
96
|
|
|
97
97
|
```json
|
|
98
|
-
"
|
|
98
|
+
"antigravityAutoPilot.dangerousCommandBlocking.customPatterns": [
|
|
99
99
|
"^my-dangerous-script",
|
|
100
100
|
"DROP TABLE"
|
|
101
101
|
]
|
package/extension.js
CHANGED
|
@@ -112,7 +112,7 @@ function getActiveBuiltinPatterns() {
|
|
|
112
112
|
* @returns {{ matched: boolean, label: string, pattern: string }}
|
|
113
113
|
*/
|
|
114
114
|
function checkDangerousCommand(cmd) {
|
|
115
|
-
const cfg = vscode.workspace.getConfiguration('
|
|
115
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
116
116
|
const enabled = cfg.get('dangerousCommandBlocking.enabled', true);
|
|
117
117
|
if (!enabled) return { matched: false, label: '', pattern: '' };
|
|
118
118
|
|
|
@@ -149,7 +149,7 @@ function checkDangerousCommand(cmd) {
|
|
|
149
149
|
* @param {string} label - Human-readable reason
|
|
150
150
|
*/
|
|
151
151
|
function handleDangerousCommand(cmd, label) {
|
|
152
|
-
const cfg = vscode.workspace.getConfiguration('
|
|
152
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
153
153
|
const action = cfg.get('dangerousCommandBlocking.action', 'block');
|
|
154
154
|
const msg = `🛡️ Dangerous command detected: "${label}" — \`${cmd.trim().substring(0, 80)}\``;
|
|
155
155
|
|
|
@@ -326,16 +326,16 @@ class AntigravityPanelProvider {
|
|
|
326
326
|
} else if (msg.command === 'toggleEnabled') {
|
|
327
327
|
autoPilotEnabled = !autoPilotEnabled;
|
|
328
328
|
updateStatusBarFromCache();
|
|
329
|
-
const cfg = vscode.workspace.getConfiguration('
|
|
329
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
330
330
|
await cfg.update('enabledOnStartup', autoPilotEnabled, vscode.ConfigurationTarget.Global);
|
|
331
331
|
if (panelProvider) panelProvider.sendEnabled(autoPilotEnabled);
|
|
332
332
|
vscode.window.showInformationMessage(
|
|
333
333
|
autoPilotEnabled ? '⚡ AutoPilot resumed' : '⏸ AutoPilot suspended',
|
|
334
334
|
);
|
|
335
335
|
} else if (msg.command === 'openSettings') {
|
|
336
|
-
vscode.commands.executeCommand('workbench.action.openSettings', '
|
|
336
|
+
vscode.commands.executeCommand('workbench.action.openSettings', 'antigravityAutoPilot');
|
|
337
337
|
} else if (msg.command === 'toggleCommandBlocking') {
|
|
338
|
-
const cfg = vscode.workspace.getConfiguration('
|
|
338
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
339
339
|
const current = cfg.get('dangerousCommandBlocking.enabled', true);
|
|
340
340
|
const next = !current;
|
|
341
341
|
await cfg.update('dangerousCommandBlocking.enabled', next, vscode.ConfigurationTarget.Global);
|
|
@@ -343,6 +343,24 @@ class AntigravityPanelProvider {
|
|
|
343
343
|
vscode.window.showInformationMessage(
|
|
344
344
|
next ? '🛡️ Command Blocking enabled' : '⚠️ Command Blocking disabled',
|
|
345
345
|
);
|
|
346
|
+
} else if (msg.command === 'toggleBrowserPermission') {
|
|
347
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
348
|
+
const current = cfg.get('browserPermission', true);
|
|
349
|
+
const next = !current;
|
|
350
|
+
await cfg.update('browserPermission', next, vscode.ConfigurationTarget.Global);
|
|
351
|
+
this.sendBrowserPermissionEnabled(next);
|
|
352
|
+
vscode.window.showInformationMessage(
|
|
353
|
+
next ? '🌐 Auto-accept browser permission enabled' : '🌐 Auto-accept browser permission disabled',
|
|
354
|
+
);
|
|
355
|
+
} else if (msg.command === 'toggleFilePermission') {
|
|
356
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
357
|
+
const current = cfg.get('filePermission', true);
|
|
358
|
+
const next = !current;
|
|
359
|
+
await cfg.update('filePermission', next, vscode.ConfigurationTarget.Global);
|
|
360
|
+
this.sendFilePermissionEnabled(next);
|
|
361
|
+
vscode.window.showInformationMessage(
|
|
362
|
+
next ? '📁 Auto-accept file permission enabled' : '📁 Auto-accept file permission disabled',
|
|
363
|
+
);
|
|
346
364
|
} else if (msg.command === 'removePattern') {
|
|
347
365
|
// Remove a built-in pattern by ID
|
|
348
366
|
const removed = getRemovedPatternIds();
|
|
@@ -362,7 +380,13 @@ class AntigravityPanelProvider {
|
|
|
362
380
|
refreshStatus();
|
|
363
381
|
this.sendEnabled(autoPilotEnabled);
|
|
364
382
|
this.sendBlockingEnabled(
|
|
365
|
-
vscode.workspace.getConfiguration('
|
|
383
|
+
vscode.workspace.getConfiguration('antigravityAutoPilot').get('dangerousCommandBlocking.enabled', true),
|
|
384
|
+
);
|
|
385
|
+
this.sendBrowserPermissionEnabled(
|
|
386
|
+
vscode.workspace.getConfiguration('antigravityAutoPilot').get('browserPermission', true),
|
|
387
|
+
);
|
|
388
|
+
this.sendFilePermissionEnabled(
|
|
389
|
+
vscode.workspace.getConfiguration('antigravityAutoPilot').get('filePermission', true),
|
|
366
390
|
);
|
|
367
391
|
this.sendPatterns();
|
|
368
392
|
}
|
|
@@ -395,6 +419,18 @@ class AntigravityPanelProvider {
|
|
|
395
419
|
this._view.webview.postMessage({ command: 'setBlockingEnabled', enabled });
|
|
396
420
|
}
|
|
397
421
|
|
|
422
|
+
/** @param {boolean} enabled */
|
|
423
|
+
sendBrowserPermissionEnabled(enabled) {
|
|
424
|
+
if (!this._view) return;
|
|
425
|
+
this._view.webview.postMessage({ command: 'setBrowserPermissionEnabled', enabled });
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** @param {boolean} enabled */
|
|
429
|
+
sendFilePermissionEnabled(enabled) {
|
|
430
|
+
if (!this._view) return;
|
|
431
|
+
this._view.webview.postMessage({ command: 'setFilePermissionEnabled', enabled });
|
|
432
|
+
}
|
|
433
|
+
|
|
398
434
|
/** Send current pattern list to the webview */
|
|
399
435
|
sendPatterns() {
|
|
400
436
|
if (!this._view) return;
|
|
@@ -633,6 +669,30 @@ class AntigravityPanelProvider {
|
|
|
633
669
|
</label>
|
|
634
670
|
</div>
|
|
635
671
|
|
|
672
|
+
<!-- Browser Permission toggle -->
|
|
673
|
+
<div class="toggle-row" id="browserPermToggleRow">
|
|
674
|
+
<div>
|
|
675
|
+
<div class="toggle-label">🌐 Browser Permission</div>
|
|
676
|
+
<div class="toggle-sub" id="browserPermToggleSub">Active — auto-accepting browser actions</div>
|
|
677
|
+
</div>
|
|
678
|
+
<label class="switch" title="Toggle auto-accept browser permission">
|
|
679
|
+
<input type="checkbox" id="browserPermToggleCheck" checked onchange="send('toggleBrowserPermission')">
|
|
680
|
+
<span class="slider"></span>
|
|
681
|
+
</label>
|
|
682
|
+
</div>
|
|
683
|
+
|
|
684
|
+
<!-- File Permission toggle -->
|
|
685
|
+
<div class="toggle-row" id="filePermToggleRow">
|
|
686
|
+
<div>
|
|
687
|
+
<div class="toggle-label">📁 File Permission</div>
|
|
688
|
+
<div class="toggle-sub" id="filePermToggleSub">Active — auto-allowing file access</div>
|
|
689
|
+
</div>
|
|
690
|
+
<label class="switch" title="Toggle auto-accept file permission">
|
|
691
|
+
<input type="checkbox" id="filePermToggleCheck" checked onchange="send('toggleFilePermission')">
|
|
692
|
+
<span class="slider"></span>
|
|
693
|
+
</label>
|
|
694
|
+
</div>
|
|
695
|
+
|
|
636
696
|
<!-- Dangerous Command Blocking section -->
|
|
637
697
|
<div class="section" id="blockSection">
|
|
638
698
|
<div class="section-header" id="blockHeader">
|
|
@@ -660,6 +720,7 @@ class AntigravityPanelProvider {
|
|
|
660
720
|
|
|
661
721
|
function send(cmd, extra) {
|
|
662
722
|
if (cmd !== 'openSettings' && cmd !== 'toggleEnabled' && cmd !== 'toggleCommandBlocking'
|
|
723
|
+
&& cmd !== 'toggleBrowserPermission' && cmd !== 'toggleFilePermission'
|
|
663
724
|
&& cmd !== 'refresh' && cmd !== 'removePattern' && cmd !== 'resetPatterns') {
|
|
664
725
|
document.getElementById('btnApply').disabled = true;
|
|
665
726
|
document.getElementById('btnRevert').disabled = true;
|
|
@@ -751,6 +812,22 @@ class AntigravityPanelProvider {
|
|
|
751
812
|
if (section) section.style.opacity = data.enabled ? '1' : '0.4';
|
|
752
813
|
}
|
|
753
814
|
|
|
815
|
+
if (data.command === 'setBrowserPermissionEnabled') {
|
|
816
|
+
const chk = document.getElementById('browserPermToggleCheck');
|
|
817
|
+
chk.checked = data.enabled;
|
|
818
|
+
document.getElementById('browserPermToggleSub').textContent = data.enabled
|
|
819
|
+
? 'Active — auto-accepting browser actions'
|
|
820
|
+
: 'Disabled — browser actions require confirmation';
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (data.command === 'setFilePermissionEnabled') {
|
|
824
|
+
const chk = document.getElementById('filePermToggleCheck');
|
|
825
|
+
chk.checked = data.enabled;
|
|
826
|
+
document.getElementById('filePermToggleSub').textContent = data.enabled
|
|
827
|
+
? 'Active — auto-allowing file access'
|
|
828
|
+
: 'Disabled — file access requires confirmation';
|
|
829
|
+
}
|
|
830
|
+
|
|
754
831
|
if (data.command === 'patterns') {
|
|
755
832
|
renderPatterns(data.patterns, data.totalBuiltin);
|
|
756
833
|
}
|
|
@@ -817,12 +894,12 @@ function activate(context) {
|
|
|
817
894
|
context.subscriptions.push(outputChannel);
|
|
818
895
|
|
|
819
896
|
// Read enabledOnStartup setting
|
|
820
|
-
const cfg = vscode.workspace.getConfiguration('
|
|
897
|
+
const cfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
821
898
|
autoPilotEnabled = cfg.get('enabledOnStartup', true);
|
|
822
899
|
|
|
823
900
|
// Status bar
|
|
824
901
|
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
|
|
825
|
-
statusBarItem.command = '
|
|
902
|
+
statusBarItem.command = 'antigravityAutoPilot.openPanel';
|
|
826
903
|
statusBarItem.text = `$(sync~spin) AG Patch`;
|
|
827
904
|
statusBarItem.tooltip = 'Checking patch status...';
|
|
828
905
|
statusBarItem.show();
|
|
@@ -832,7 +909,7 @@ function activate(context) {
|
|
|
832
909
|
panelProvider = new AntigravityPanelProvider(context);
|
|
833
910
|
context.subscriptions.push(
|
|
834
911
|
vscode.window.registerWebviewViewProvider(
|
|
835
|
-
'
|
|
912
|
+
'antigravityAutoPilot.panel',
|
|
836
913
|
panelProvider,
|
|
837
914
|
{ webviewOptions: { retainContextWhenHidden: true } },
|
|
838
915
|
),
|
|
@@ -855,8 +932,8 @@ function activate(context) {
|
|
|
855
932
|
// Config change listener
|
|
856
933
|
context.subscriptions.push(
|
|
857
934
|
vscode.workspace.onDidChangeConfiguration((e) => {
|
|
858
|
-
if (e.affectsConfiguration('
|
|
859
|
-
autoPilotEnabled = vscode.workspace.getConfiguration('
|
|
935
|
+
if (e.affectsConfiguration('antigravityAutoPilot.enabledOnStartup')) {
|
|
936
|
+
autoPilotEnabled = vscode.workspace.getConfiguration('antigravityAutoPilot').get('enabledOnStartup', true);
|
|
860
937
|
updateStatusBarFromCache();
|
|
861
938
|
if (panelProvider) panelProvider.sendEnabled(autoPilotEnabled);
|
|
862
939
|
}
|
|
@@ -865,18 +942,18 @@ function activate(context) {
|
|
|
865
942
|
|
|
866
943
|
// Commands
|
|
867
944
|
context.subscriptions.push(
|
|
868
|
-
vscode.commands.registerCommand('
|
|
945
|
+
vscode.commands.registerCommand('antigravityAutoPilot.applyPatch', async () => {
|
|
869
946
|
const result = await applyPatch();
|
|
870
947
|
vscode.window.showInformationMessage(result.message);
|
|
871
948
|
}),
|
|
872
|
-
vscode.commands.registerCommand('
|
|
949
|
+
vscode.commands.registerCommand('antigravityAutoPilot.revertPatch', async () => {
|
|
873
950
|
const result = await revertPatch();
|
|
874
951
|
vscode.window.showInformationMessage(result.message);
|
|
875
952
|
}),
|
|
876
|
-
vscode.commands.registerCommand('
|
|
877
|
-
vscode.commands.executeCommand('
|
|
953
|
+
vscode.commands.registerCommand('antigravityAutoPilot.openPanel', () => {
|
|
954
|
+
vscode.commands.executeCommand('antigravityAutoPilot.panel.focus');
|
|
878
955
|
}),
|
|
879
|
-
vscode.commands.registerCommand('
|
|
956
|
+
vscode.commands.registerCommand('antigravityAutoPilot.checkStatus', async () => {
|
|
880
957
|
const status = await getPatchStatus();
|
|
881
958
|
if (!status.basePath) {
|
|
882
959
|
vscode.window.showWarningMessage('Antigravity not found!');
|
|
@@ -898,7 +975,7 @@ function activate(context) {
|
|
|
898
975
|
panelProvider.sendEnabled(autoPilotEnabled);
|
|
899
976
|
}
|
|
900
977
|
|
|
901
|
-
const startCfg = vscode.workspace.getConfiguration('
|
|
978
|
+
const startCfg = vscode.workspace.getConfiguration('antigravityAutoPilot');
|
|
902
979
|
if (startCfg.get('applyOnStartup') && !status.patched && status.basePath) {
|
|
903
980
|
const result = await applyPatch();
|
|
904
981
|
if (result.success) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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.4.
|
|
5
|
+
"version": "1.4.5",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publisher": "nguyen-hoang",
|
|
8
8
|
"bin": {
|
|
@@ -37,57 +37,57 @@
|
|
|
37
37
|
"antigravity-autopilot": [
|
|
38
38
|
{
|
|
39
39
|
"type": "webview",
|
|
40
|
-
"id": "
|
|
40
|
+
"id": "antigravityAutoPilot.panel",
|
|
41
41
|
"name": "AutoPilot"
|
|
42
42
|
}
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
45
|
"commands": [
|
|
46
46
|
{
|
|
47
|
-
"command": "
|
|
47
|
+
"command": "antigravityAutoPilot.applyPatch",
|
|
48
48
|
"title": "Antigravity: Apply AutoPilot Patch",
|
|
49
49
|
"icon": "$(zap)"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
|
-
"command": "
|
|
52
|
+
"command": "antigravityAutoPilot.revertPatch",
|
|
53
53
|
"title": "Antigravity: Revert AutoPilot Patch",
|
|
54
54
|
"icon": "$(discard)"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
"command": "
|
|
57
|
+
"command": "antigravityAutoPilot.checkStatus",
|
|
58
58
|
"title": "Antigravity: Check Patch Status",
|
|
59
59
|
"icon": "$(info)"
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
|
-
"command": "
|
|
62
|
+
"command": "antigravityAutoPilot.openPanel",
|
|
63
63
|
"title": "Antigravity: Open AutoPilot Panel"
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
66
|
"keybindings": [
|
|
67
67
|
{
|
|
68
|
-
"command": "
|
|
68
|
+
"command": "antigravityAutoPilot.applyPatch",
|
|
69
69
|
"key": "ctrl+shift+f12"
|
|
70
70
|
}
|
|
71
71
|
],
|
|
72
72
|
"configuration": {
|
|
73
73
|
"title": "Antigravity AutoPilot",
|
|
74
74
|
"properties": {
|
|
75
|
-
"
|
|
75
|
+
"antigravityAutoPilot.applyOnStartup": {
|
|
76
76
|
"type": "boolean",
|
|
77
77
|
"default": false,
|
|
78
78
|
"description": "Automatically apply the AutoPilot patch when VS Code starts. Safe to enable — patch is idempotent."
|
|
79
79
|
},
|
|
80
|
-
"
|
|
80
|
+
"antigravityAutoPilot.enabledOnStartup": {
|
|
81
81
|
"type": "boolean",
|
|
82
82
|
"default": true,
|
|
83
83
|
"description": "Keep AutoPilot enabled (active) when VS Code starts. When disabled, AutoPilot will be suspended until manually turned on from the sidebar."
|
|
84
84
|
},
|
|
85
|
-
"
|
|
85
|
+
"antigravityAutoPilot.dangerousCommandBlocking.enabled": {
|
|
86
86
|
"type": "boolean",
|
|
87
87
|
"default": true,
|
|
88
88
|
"description": "Block dangerous terminal commands (e.g. rm -rf /, format C:) before they execute. Fully customizable via the blocklist setting."
|
|
89
89
|
},
|
|
90
|
-
"
|
|
90
|
+
"antigravityAutoPilot.dangerousCommandBlocking.action": {
|
|
91
91
|
"type": "string",
|
|
92
92
|
"enum": [
|
|
93
93
|
"block",
|
|
@@ -102,13 +102,23 @@
|
|
|
102
102
|
"default": "block",
|
|
103
103
|
"description": "Action to take when a dangerous command is detected."
|
|
104
104
|
},
|
|
105
|
-
"
|
|
105
|
+
"antigravityAutoPilot.dangerousCommandBlocking.customPatterns": {
|
|
106
106
|
"type": "array",
|
|
107
107
|
"items": {
|
|
108
108
|
"type": "string"
|
|
109
109
|
},
|
|
110
110
|
"default": [],
|
|
111
111
|
"description": "Additional regex patterns (JavaScript syntax) to treat as dangerous commands. Example: [\"^dd if=.*of=/dev/sd\", \"^shred\"]"
|
|
112
|
+
},
|
|
113
|
+
"antigravityAutoPilot.browserPermission": {
|
|
114
|
+
"type": "boolean",
|
|
115
|
+
"default": true,
|
|
116
|
+
"description": "Automatically accept browser action permissions (e.g. 'Agent needs permission to act on chromewebdata'). Requires patch to be applied."
|
|
117
|
+
},
|
|
118
|
+
"antigravityAutoPilot.filePermission": {
|
|
119
|
+
"type": "boolean",
|
|
120
|
+
"default": true,
|
|
121
|
+
"description": "Automatically allow file access permissions with conversation scope. Requires patch to be applied."
|
|
112
122
|
}
|
|
113
123
|
}
|
|
114
124
|
}
|
package/patcher.js
CHANGED
|
@@ -95,7 +95,7 @@ function getTargetFiles(basePath) {
|
|
|
95
95
|
* Port of: https://github.com/Kanezal/better-antigravity/blob/main/fixes/auto-run-fix/patch.js
|
|
96
96
|
*/
|
|
97
97
|
function analyzeFile(content, label) {
|
|
98
|
-
const log = (msg) => process.send({ type: 'log', msg: `[
|
|
98
|
+
const log = (msg) => process.send({ type: 'log', msg: `[AutoPilot] [${label}] ${msg}` });
|
|
99
99
|
|
|
100
100
|
// 1. Find the onChange handler: contains setTerminalAutoExecutionPolicy AND .EAGER
|
|
101
101
|
// Pattern: VARNAME=CALLBACK(ARG=>{...setTerminalAutoExecutionPolicy...,ARG===ENUM.EAGER&&CONFIRM(!0)},[...])
|
|
@@ -189,13 +189,170 @@ function analyzeFile(content, label) {
|
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
// ─── Browser Action Permission (auto-confirm) ───────────────────────────────
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Finds the JPc browser-action confirmation component and builds auto-confirm patch.
|
|
196
|
+
* Pattern: COMP=({sourceTrajectoryStepInfo:VAR,...,url:VAR})=>{...CONFIRM_FN=Mt(()=>{SEND(Ui(MSG,{...,interaction:{case:"browserAction",value:Ui(TYPE,{confirm:!0})}}))},...)...}
|
|
197
|
+
*/
|
|
198
|
+
function analyzeBrowserAction(content, label) {
|
|
199
|
+
const log = (msg) => process.send({ type: 'log', msg: `[AutoPilot] [${label}] [browser] ${msg}` });
|
|
200
|
+
|
|
201
|
+
// 1. Find the browserAction confirm:!0 callback pattern
|
|
202
|
+
// VAR=Mt(()=>{SEND(Ui(MSG,{trajectoryId:VAR,stepIndex:VAR,interaction:{case:"browserAction",value:Ui(TYPE,{confirm:!0})}}))},DEPS)
|
|
203
|
+
const confirmRe = /(\w+)=Mt\(\(\)=>\{(\w+)\(Ui\((\w+),\{trajectoryId:(\w+),stepIndex:(\w+),interaction:\{case:"browserAction",value:Ui\((\w+),\{confirm:!0\}\)\}\}\)\)\},\[([\w,]*)\]\)/;
|
|
204
|
+
const confirmMatch = content.match(confirmRe);
|
|
205
|
+
|
|
206
|
+
if (!confirmMatch) {
|
|
207
|
+
log('❌ Could not find browserAction confirm pattern');
|
|
208
|
+
const idx = content.indexOf('browserAction');
|
|
209
|
+
if (idx >= 0) {
|
|
210
|
+
log(` Context: ...${content.slice(Math.max(0, idx - 80), idx + 120)}...`);
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const [fullMatch, confirmVar] = confirmMatch;
|
|
216
|
+
const matchIndex = content.indexOf(fullMatch);
|
|
217
|
+
log(`✓ Found browserAction confirm at offset ${matchIndex}`);
|
|
218
|
+
log(` confirmVar=${confirmVar}`);
|
|
219
|
+
|
|
220
|
+
// 2. Find useEffect alias (reuse from nearby code)
|
|
221
|
+
const nearbyCode = content.substring(Math.max(0, matchIndex - 5000), matchIndex + 5000);
|
|
222
|
+
const effectCandidates = {};
|
|
223
|
+
const effectRe = /\b(\w{2,3})\(\(\)=>\{[^}]{3,80}\},\[/g;
|
|
224
|
+
let m;
|
|
225
|
+
while ((m = effectRe.exec(nearbyCode)) !== null) {
|
|
226
|
+
const alias = m[1];
|
|
227
|
+
if (alias !== 'Mt' && alias !== 'Vi' && alias !== 'var' && alias !== 'new') {
|
|
228
|
+
effectCandidates[alias] = (effectCandidates[alias] || 0) + 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const cleanupRe = /\b(\w{2,3})\(\(\)=>\{[^}]*return\s*\(\)=>/g;
|
|
232
|
+
while ((m = cleanupRe.exec(content)) !== null) {
|
|
233
|
+
const alias = m[1];
|
|
234
|
+
if (alias !== 'Mt' && alias !== 'Vi') {
|
|
235
|
+
effectCandidates[alias] = (effectCandidates[alias] || 0) + 5;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
let useEffectAlias = null;
|
|
239
|
+
let maxCount = 0;
|
|
240
|
+
for (const [alias, count] of Object.entries(effectCandidates)) {
|
|
241
|
+
if (count > maxCount) {
|
|
242
|
+
maxCount = count;
|
|
243
|
+
useEffectAlias = alias;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (!useEffectAlias) {
|
|
247
|
+
log('❌ Could not determine useEffect alias');
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
log(` useEffect=${useEffectAlias} (confidence: ${maxCount} hits)`);
|
|
251
|
+
|
|
252
|
+
// 3. Build patch — auto-call confirmVar() on mount
|
|
253
|
+
const patchCode = `_abp=${useEffectAlias}(()=>{${confirmVar}()},[${confirmVar}]),`;
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
target: fullMatch,
|
|
257
|
+
replacement: patchCode + fullMatch,
|
|
258
|
+
patchMarker: `_abp=${useEffectAlias}(()=>{${confirmVar}()}`,
|
|
259
|
+
label
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ─── File Access Permission (auto-allow with conversation scope) ─────────────
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Finds the rBe file-permission component and builds auto-allow patch.
|
|
267
|
+
* Pattern: COMP=({sourceTrajectoryStepInfo:VAR,req:VAR,status:VAR})=>{...SEND_FN...filePermission...scope...}
|
|
268
|
+
*/
|
|
269
|
+
function analyzeFilePermission(content, label) {
|
|
270
|
+
const log = (msg) => process.send({ type: 'log', msg: `[AutoPilot] [${label}] [file] ${msg}` });
|
|
271
|
+
|
|
272
|
+
// 1. Find the filePermission sender pattern
|
|
273
|
+
// VAR=(ALLOW_VAR,SCOPE_VAR)=>{SEND(Ui(MSG,{trajectoryId:VAR,stepIndex:VAR,interaction:{case:"filePermission",value:Ui(TYPE,{allow:ALLOW_VAR,scope:SCOPE_VAR,absolutePathUri:REQ.absolutePathUri})}}))};
|
|
274
|
+
const senderRe = /(\w+)=\((\w+),(\w+)\)=>\{(\w+)\(Ui\((\w+),\{trajectoryId:(\w+),stepIndex:(\w+),interaction:\{case:"filePermission",value:Ui\((\w+),\{allow:\2,scope:\3,absolutePathUri:(\w+)\.absolutePathUri\}\)\}\}\)\)\}/;
|
|
275
|
+
const senderMatch = content.match(senderRe);
|
|
276
|
+
|
|
277
|
+
if (!senderMatch) {
|
|
278
|
+
log('❌ Could not find filePermission sender pattern');
|
|
279
|
+
const idx = content.indexOf('filePermission');
|
|
280
|
+
if (idx >= 0) {
|
|
281
|
+
log(` Context: ...${content.slice(Math.max(0, idx - 80), idx + 120)}...`);
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const [fullMatch, senderVar, , , , , , , , reqVar] = senderMatch;
|
|
287
|
+
const matchIndex = content.indexOf(fullMatch);
|
|
288
|
+
log(`✓ Found filePermission sender at offset ${matchIndex}`);
|
|
289
|
+
log(` senderVar=${senderVar}, reqVar=${reqVar}`);
|
|
290
|
+
|
|
291
|
+
// 2. Find the scope enum (kot) — look for kot.CONVERSATION or similar near filePermission
|
|
292
|
+
// Pattern: o(!0,ENUM.CONVERSATION) in the Allow This Conversation button
|
|
293
|
+
const scopeRe = new RegExp(`${senderVar.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\(!0,(\w+)\.CONVERSATION\)`);
|
|
294
|
+
const scopeMatch = content.substring(matchIndex, matchIndex + 2000).match(scopeRe);
|
|
295
|
+
|
|
296
|
+
if (!scopeMatch) {
|
|
297
|
+
log('❌ Could not find scope enum (CONVERSATION)');
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
const scopeEnum = scopeMatch[1];
|
|
301
|
+
log(` scopeEnum=${scopeEnum}`);
|
|
302
|
+
|
|
303
|
+
// 3. Find useEffect alias
|
|
304
|
+
const nearbyCode = content.substring(Math.max(0, matchIndex - 5000), matchIndex + 5000);
|
|
305
|
+
const effectCandidates = {};
|
|
306
|
+
const effectRe = /\b(\w{2,3})\(\(\)=>\{[^}]{3,80}\},\[/g;
|
|
307
|
+
let m2;
|
|
308
|
+
while ((m2 = effectRe.exec(nearbyCode)) !== null) {
|
|
309
|
+
const alias = m2[1];
|
|
310
|
+
if (alias !== 'Mt' && alias !== 'Vi' && alias !== 'var' && alias !== 'new') {
|
|
311
|
+
effectCandidates[alias] = (effectCandidates[alias] || 0) + 1;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const cleanupRe = /\b(\w{2,3})\(\(\)=>\{[^}]*return\s*\(\)=>/g;
|
|
315
|
+
while ((m2 = cleanupRe.exec(content)) !== null) {
|
|
316
|
+
const alias = m2[1];
|
|
317
|
+
if (alias !== 'Mt' && alias !== 'Vi') {
|
|
318
|
+
effectCandidates[alias] = (effectCandidates[alias] || 0) + 5;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
let useEffectAlias = null;
|
|
322
|
+
let maxCount = 0;
|
|
323
|
+
for (const [alias, count] of Object.entries(effectCandidates)) {
|
|
324
|
+
if (count > maxCount) {
|
|
325
|
+
maxCount = count;
|
|
326
|
+
useEffectAlias = alias;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (!useEffectAlias) {
|
|
330
|
+
log('❌ Could not determine useEffect alias');
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
log(` useEffect=${useEffectAlias} (confidence: ${maxCount} hits)`);
|
|
334
|
+
|
|
335
|
+
// 4. Build patch — auto-call senderVar(!0, scopeEnum.CONVERSATION) on mount
|
|
336
|
+
const patchCode = `_afp=${useEffectAlias}(()=>{${senderVar}(!0,${scopeEnum}.CONVERSATION)},[${senderVar}]),`;
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
target: fullMatch,
|
|
340
|
+
replacement: patchCode + fullMatch,
|
|
341
|
+
patchMarker: `_afp=${useEffectAlias}(()=>{${senderVar}(!0,${scopeEnum}.CONVERSATION)`,
|
|
342
|
+
label
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
192
346
|
// ─── File Operations ─────────────────────────────────────────────────────────
|
|
193
347
|
|
|
194
348
|
function isFilePatched(filePath) {
|
|
195
349
|
if (!fs.existsSync(filePath)) return false;
|
|
196
350
|
try {
|
|
197
351
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
198
|
-
|
|
352
|
+
const hasTerminal = content.includes('_aep=') && /_aep=\w+\(\(\)=>\{[^}]+EAGER/.test(content);
|
|
353
|
+
const hasBrowser = content.includes('_abp=') && /_abp=\w+\(\(\)=>\{\w+\(\)\}/.test(content);
|
|
354
|
+
const hasFile = content.includes('_afp=') && /_afp=\w+\(\(\)=>\{\w+\(!0,/.test(content);
|
|
355
|
+
return hasTerminal || hasBrowser || hasFile;
|
|
199
356
|
} catch {
|
|
200
357
|
return false;
|
|
201
358
|
}
|
|
@@ -203,7 +360,7 @@ function isFilePatched(filePath) {
|
|
|
203
360
|
|
|
204
361
|
function patchFile(filePath, label) {
|
|
205
362
|
if (!fs.existsSync(filePath)) {
|
|
206
|
-
process.send({ type: 'log', msg: `[
|
|
363
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⏭️ [${label}] File not found, skipping` });
|
|
207
364
|
return true; // optional file missing is not a failure
|
|
208
365
|
}
|
|
209
366
|
|
|
@@ -211,48 +368,92 @@ function patchFile(filePath, label) {
|
|
|
211
368
|
try {
|
|
212
369
|
content = fs.readFileSync(filePath, 'utf8');
|
|
213
370
|
} catch (e) {
|
|
214
|
-
process.send({ type: 'log', msg: `[
|
|
371
|
+
process.send({ type: 'log', msg: `[AutoPilot] ❌ [${label}] Read error: ${e.message}` });
|
|
215
372
|
return false;
|
|
216
373
|
}
|
|
217
374
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
375
|
+
// Backup original (before any patching)
|
|
376
|
+
const bakPath = filePath + '.bak';
|
|
377
|
+
if (!fs.existsSync(bakPath)) {
|
|
378
|
+
fs.copyFileSync(filePath, bakPath);
|
|
379
|
+
process.send({ type: 'log', msg: `[AutoPilot] 📦 [${label}] Backup created` });
|
|
221
380
|
}
|
|
222
381
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
382
|
+
let patched = content;
|
|
383
|
+
let anyPatched = false;
|
|
384
|
+
|
|
385
|
+
// ── Terminal auto-execute patch ──
|
|
386
|
+
if (!content.includes('_aep=')) {
|
|
387
|
+
const analysis = analyzeFile(content, label);
|
|
388
|
+
if (analysis) {
|
|
389
|
+
const count = patched.split(analysis.target).length - 1;
|
|
390
|
+
if (count === 1) {
|
|
391
|
+
patched = patched.replace(analysis.target, analysis.replacement);
|
|
392
|
+
anyPatched = true;
|
|
393
|
+
process.send({ type: 'log', msg: `[AutoPilot] ✅ [${label}] Terminal auto-execute patched` });
|
|
394
|
+
} else {
|
|
395
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⚠️ [${label}] Terminal target found ${count}x (expected 1)` });
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⏭️ [${label}] Terminal already patched` });
|
|
231
400
|
}
|
|
232
401
|
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
402
|
+
// ── Browser action auto-confirm patch ──
|
|
403
|
+
if (!patched.includes('_abp=')) {
|
|
404
|
+
const browserAnalysis = analyzeBrowserAction(patched, label);
|
|
405
|
+
if (browserAnalysis) {
|
|
406
|
+
const count = patched.split(browserAnalysis.target).length - 1;
|
|
407
|
+
if (count === 1) {
|
|
408
|
+
patched = patched.replace(browserAnalysis.target, browserAnalysis.replacement);
|
|
409
|
+
anyPatched = true;
|
|
410
|
+
process.send({ type: 'log', msg: `[AutoPilot] ✅ [${label}] Browser action auto-confirm patched` });
|
|
411
|
+
} else {
|
|
412
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⚠️ [${label}] Browser target found ${count}x (expected 1)` });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⏭️ [${label}] Browser action already patched` });
|
|
238
417
|
}
|
|
239
418
|
|
|
240
|
-
|
|
241
|
-
|
|
419
|
+
// ── File permission auto-allow patch ──
|
|
420
|
+
if (!patched.includes('_afp=')) {
|
|
421
|
+
const fileAnalysis = analyzeFilePermission(patched, label);
|
|
422
|
+
if (fileAnalysis) {
|
|
423
|
+
const count = patched.split(fileAnalysis.target).length - 1;
|
|
424
|
+
if (count === 1) {
|
|
425
|
+
patched = patched.replace(fileAnalysis.target, fileAnalysis.replacement);
|
|
426
|
+
anyPatched = true;
|
|
427
|
+
process.send({ type: 'log', msg: `[AutoPilot] ✅ [${label}] File permission auto-allow patched` });
|
|
428
|
+
} else {
|
|
429
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⚠️ [${label}] File target found ${count}x (expected 1)` });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
} else {
|
|
433
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⏭️ [${label}] File permission already patched` });
|
|
434
|
+
}
|
|
242
435
|
|
|
243
|
-
|
|
244
|
-
|
|
436
|
+
if (anyPatched) {
|
|
437
|
+
fs.writeFileSync(filePath, patched, 'utf8');
|
|
438
|
+
const sizeDiff = fs.statSync(filePath).size - fs.statSync(bakPath).size;
|
|
439
|
+
process.send({ type: 'log', msg: `[AutoPilot] ✅ [${label}] All patches applied (+${sizeDiff} bytes)` });
|
|
440
|
+
} else if (!content.includes('_aep=') && !content.includes('_abp=') && !content.includes('_afp=')) {
|
|
441
|
+
process.send({ type: 'log', msg: `[AutoPilot] ❌ [${label}] No patches could be applied` });
|
|
442
|
+
return false;
|
|
443
|
+
} else {
|
|
444
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⏭️ [${label}] All patches already applied` });
|
|
445
|
+
}
|
|
245
446
|
return true;
|
|
246
447
|
}
|
|
247
448
|
|
|
248
449
|
function revertFile(filePath, label) {
|
|
249
450
|
const bak = filePath + '.bak';
|
|
250
451
|
if (!fs.existsSync(bak)) {
|
|
251
|
-
process.send({ type: 'log', msg: `[
|
|
452
|
+
process.send({ type: 'log', msg: `[AutoPilot] ⏭️ [${label}] No backup, skipping` });
|
|
252
453
|
return;
|
|
253
454
|
}
|
|
254
455
|
fs.copyFileSync(bak, filePath);
|
|
255
|
-
process.send({ type: 'log', msg: `[
|
|
456
|
+
process.send({ type: 'log', msg: `[AutoPilot] ✅ [${label}] Reverted` });
|
|
256
457
|
}
|
|
257
458
|
|
|
258
459
|
// ─── Message Handler ──────────────────────────────────────────────────────────
|
|
@@ -266,11 +467,23 @@ process.on('message', (msg) => {
|
|
|
266
467
|
process.exit(0);
|
|
267
468
|
return;
|
|
268
469
|
}
|
|
269
|
-
const files = getTargetFiles(basePath).map(f =>
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
470
|
+
const files = getTargetFiles(basePath).map(f => {
|
|
471
|
+
let patchDetails = { terminal: false, browser: false, file: false };
|
|
472
|
+
if (fs.existsSync(f.filePath)) {
|
|
473
|
+
try {
|
|
474
|
+
const fc = fs.readFileSync(f.filePath, 'utf8');
|
|
475
|
+
patchDetails.terminal = fc.includes('_aep=') && /_aep=\w+\(\(\)=>\{[^}]+EAGER/.test(fc);
|
|
476
|
+
patchDetails.browser = fc.includes('_abp=') && /_abp=\w+\(\(\)=>\{\w+\(\)\}/.test(fc);
|
|
477
|
+
patchDetails.file = fc.includes('_afp=') && /_afp=\w+\(\(\)=>\{\w+\(!0,/.test(fc);
|
|
478
|
+
} catch { }
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
label: f.label,
|
|
482
|
+
patched: patchDetails.terminal || patchDetails.browser || patchDetails.file,
|
|
483
|
+
patchDetails,
|
|
484
|
+
exists: fs.existsSync(f.filePath),
|
|
485
|
+
};
|
|
486
|
+
});
|
|
274
487
|
process.send({ type: 'status', basePath, files });
|
|
275
488
|
process.exit(0);
|
|
276
489
|
|
|
@@ -288,7 +501,7 @@ process.on('message', (msg) => {
|
|
|
288
501
|
success,
|
|
289
502
|
message: success
|
|
290
503
|
? '✅ Patch thành công! Restart Antigravity để áp dụng.'
|
|
291
|
-
: '⚠️ Một số file không patch được. Xem Output >
|
|
504
|
+
: '⚠️ Một số file không patch được. Xem Output > AutoPilot để biết chi tiết.',
|
|
292
505
|
});
|
|
293
506
|
process.exit(success ? 0 : 1);
|
|
294
507
|
|