antigravity-tc 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.id.md +146 -0
- package/README.md +84 -73
- package/bin/restart.js +133 -0
- package/build.md +2 -0
- package/index.js +44 -2
- package/package.json +5 -3
- package/server.js +619 -50
- package/src/config.js +3 -0
- package/src/portal-defaults.js +147 -0
- package/src/tray.js +11 -0
- package/web/dist/admin.html +4 -4
- package/web/dist/assets/admin-C6nRfkO4.css +1 -0
- package/web/dist/assets/admin-CysSxUuD.js +3 -0
- package/web/dist/assets/index-9jTcCVxG.js +1 -0
- package/web/dist/assets/index-tUrCVzDv.css +1 -0
- package/web/dist/assets/styles-BYH11bD8.js +2 -0
- package/web/dist/assets/styles-akdfcIjf.css +1 -0
- package/web/dist/index.html +4 -4
- package/web/dist/assets/admin-DPInPm4J.css +0 -1
- package/web/dist/assets/admin-z_Di_0VN.js +0 -3
- package/web/dist/assets/index-BBB1az1b.js +0 -1
- package/web/dist/assets/index-Cb27-wjB.css +0 -1
- package/web/dist/assets/styles-WqBkvfmY.css +0 -1
- package/web/dist/assets/styles-pGt3BQwq.js +0 -2
package/README.id.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="images/antigravity-tc.jpg" alt="Antigravity Token Collector" width="860" />
|
|
4
|
+
|
|
5
|
+
# Antigravity Token Collector
|
|
6
|
+
|
|
7
|
+
**Kumpulkan donasi token Antigravity dari siapa saja — langsung masuk ke database [9Router](https://github.com/decolua/9router) Anda.**
|
|
8
|
+
|
|
9
|
+
[English](README.md) | Bahasa Indonesia (Tersedia dalam 2 Bahasa / Available in 2 Languages)
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/antigravity-tc)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](#-dukungan-platform)
|
|
14
|
+
[]()
|
|
15
|
+
|
|
16
|
+
Tray app + dashboard untuk mengelola donasi token: halaman donasi publik, portal yang bisa dikustom, multi bahasa, tunnel gratis tanpa expose IP, auto-start saat login, dan sync massal dua arah dengan 9Router.
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ⚡ Quick Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g antigravity-tc
|
|
26
|
+
antigravity-tc
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Dashboard terbuka di `http://localhost:3456/dashboard` — tray icon muncul di menubar.
|
|
30
|
+
|
|
31
|
+
> Password default: `1234567890`. Segera ganti di **Pengaturan → Keamanan**.
|
|
32
|
+
>
|
|
33
|
+
> Lupa password? Jalankan `antigravity-tc-reset-password`.
|
|
34
|
+
|
|
35
|
+
## 🔄 Cara Kerja
|
|
36
|
+
|
|
37
|
+
1. Jalankan `antigravity-tc`.
|
|
38
|
+
2. Buat link donasi personal dari dashboard, atau aktifkan tunnel publik.
|
|
39
|
+
3. Donatur login Google + tempel kode.
|
|
40
|
+
4. Token dicek eligibility, di-refresh bila expired, lalu bisa disinkronkan ke 9Router.
|
|
41
|
+
5. Halaman depan bisa disesuaikan dari **Pengaturan → Portal Settings**.
|
|
42
|
+
|
|
43
|
+
## 🖼️ Tampilan
|
|
44
|
+
|
|
45
|
+
| Dashboard | Sync Massal | Pengaturan |
|
|
46
|
+
| :---: | :---: | :---: |
|
|
47
|
+
|  |  |  |
|
|
48
|
+
|
|
49
|
+
## 📋 Fitur
|
|
50
|
+
|
|
51
|
+
| Fitur | Keterangan |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| Halaman donasi publik | Login Google + tempel kode, token dicek eligibility lalu disimpan |
|
|
54
|
+
| Portal Settings | Atur layout dan kata-kata halaman depan; data disimpan di aplikasi, bukan DB 9Router |
|
|
55
|
+
| Multi bahasa | UI dashboard dan portal multibahasa (Bahasa Indonesia & English) |
|
|
56
|
+
| Generate link personal | `?for=Nama` untuk sapaan otomatis |
|
|
57
|
+
| Dashboard admin | Statistik, tabel live, search, filter status, sumber, dan tier, export/import CSV |
|
|
58
|
+
| Deteksi & Filter Tier | Menampilkan tier donasi (**Free**, **Plus**, **Pro**, **Ultra**) serta filter cepat di tabel |
|
|
59
|
+
| Export Go Keyring | Salin token donatur format `go-keyring-base64` untuk login paksa ke Antigravity / `antigravity-cli` |
|
|
60
|
+
| Sync ke 9Router | Upsert semua donation logs ke providerConnections 9Router |
|
|
61
|
+
| Sync dari 9Router | Ambil providerConnections 9Router ke donation logs lokal |
|
|
62
|
+
| Check ALL Eligibility | Cek semua row bertoken dengan jeda aman dan rekap status |
|
|
63
|
+
| Auto refresh token | Token expired dicoba refresh sebelum check eligibility |
|
|
64
|
+
| Tunnel publik gratis | Cloudflare Quick Tunnel untuk URL publik |
|
|
65
|
+
| Restart Services | Restart dari tray atau tombol Settings setelah perubahan config |
|
|
66
|
+
| Auto start | Berjalan otomatis mode tray saat OS login |
|
|
67
|
+
| Keamanan | Login JWT, secret unik per instalasi, tunnel terkunci selama password default |
|
|
68
|
+
|
|
69
|
+
## 🚀 Login ke Official Apps (Antigravity & antigravity-cli)
|
|
70
|
+
|
|
71
|
+
Anda dapat menggunakan token donatur untuk langsung login ke aplikasi resmi **Antigravity** atau **antigravity-cli** tanpa perlu autentikasi ulang via browser:
|
|
72
|
+
|
|
73
|
+
1. Di tabel donasi admin, klik tombol aksi (**...**) pada baris donatur → pilih **Go Keyring**.
|
|
74
|
+
2. Salin string `go-keyring-base64:...` atau langsung gunakan perintah terminal yang disediakan:
|
|
75
|
+
- **macOS (Keychain)**:
|
|
76
|
+
```bash
|
|
77
|
+
security add-generic-password -s gemini -a antigravity -w "<STRING_KEYRING>" -U
|
|
78
|
+
```
|
|
79
|
+
- **Windows (CMD / PowerShell)**:
|
|
80
|
+
```powershell
|
|
81
|
+
cmdkey /generic:"gemini:antigravity" /user:"antigravity" /pass:"<STRING_KEYRING>"
|
|
82
|
+
```
|
|
83
|
+
*(Atau isi manual via **Windows Credential Manager** → Generic Credentials).*
|
|
84
|
+
3. Buka Antigravity atau jalankan `antigravity-cli` — sesi login donatur langsung aktif.
|
|
85
|
+
|
|
86
|
+
## 📁 Lokasi Data
|
|
87
|
+
|
|
88
|
+
### Database 9Router
|
|
89
|
+
|
|
90
|
+
| OS | Lokasi Default |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| macOS / Linux | `~/.9router/db/data.sqlite` |
|
|
93
|
+
| Windows | `%APPDATA%/9router/db/data.sqlite` |
|
|
94
|
+
| Docker | `/app/data/db/data.sqlite` |
|
|
95
|
+
|
|
96
|
+
Path bisa diganti via **Dashboard → Pengaturan → Database 9Router** atau env `DB_PATH`. Perubahan path perlu restart aplikasi.
|
|
97
|
+
|
|
98
|
+
### Data ATC
|
|
99
|
+
|
|
100
|
+
| OS | Lokasi |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| macOS / Linux | `~/.antigravity-tc/` |
|
|
103
|
+
| Windows | `%USERPROFILE%\.antigravity-tc\` |
|
|
104
|
+
| Docker | `/root/.antigravity-tc/` |
|
|
105
|
+
|
|
106
|
+
| Isi | Keterangan |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| `.env` | Konfigurasi lokal |
|
|
109
|
+
| `logs/donation-logs.sqlite` | Log donasi |
|
|
110
|
+
| `bin/cloudflared` | Binary tunnel |
|
|
111
|
+
| Config aplikasi | Password admin, portal settings, bahasa, auto-start, path DB |
|
|
112
|
+
|
|
113
|
+
## 🖥️ Dukungan Platform
|
|
114
|
+
|
|
115
|
+
| Kemampuan | macOS | Linux | Windows | Docker |
|
|
116
|
+
| --- | :---: | :---: | :---: | :---: |
|
|
117
|
+
| Server + Dashboard + halaman donasi | ✅ | ✅ | ✅ | ✅ |
|
|
118
|
+
| Tray icon | ✅ | ✅ | ✅ | — |
|
|
119
|
+
| Auto-start saat login | ✅ | ✅ | ✅ | — |
|
|
120
|
+
| Cloudflare Tunnel | ✅ | ✅ | ✅ | ✅ |
|
|
121
|
+
| Path DB 9Router otomatis per OS | ✅ | ✅ | ✅ | ✅ |
|
|
122
|
+
|
|
123
|
+
## 🔑 Password & `.env`
|
|
124
|
+
|
|
125
|
+
- Password default: `1234567890`.
|
|
126
|
+
- Prioritas password: dashboard > `APP_PASSWORD` > default.
|
|
127
|
+
- Kredensial OAuth publik Antigravity CLI sudah tertanam bawaan.
|
|
128
|
+
- Override `OAUTH_CLIENT_ID` / `OAUTH_CLIENT_SECRET` tersedia bila perlu.
|
|
129
|
+
|
|
130
|
+
## ❓ Troubleshooting
|
|
131
|
+
|
|
132
|
+
| Masalah | Solusi |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| Lupa password admin | Jalankan `antigravity-tc-reset-password` |
|
|
135
|
+
| Tunnel tidak bisa diaktifkan | Ganti password default dulu |
|
|
136
|
+
| Tray icon tidak muncul | Pastikan binary `systray2/traybin/` executable |
|
|
137
|
+
| DB 9Router tidak ketemu | Cek path di Pengaturan → Database 9Router, lalu restart services |
|
|
138
|
+
| Refresh token gagal | Donatur perlu login ulang bila Google menolak refresh token |
|
|
139
|
+
|
|
140
|
+
## 🛠️ Development
|
|
141
|
+
|
|
142
|
+
Lihat [dev.md](dev.md) dan [build.md](build.md).
|
|
143
|
+
|
|
144
|
+
## 📄 License
|
|
145
|
+
|
|
146
|
+
[MIT](LICENSE) © decolua and contributors
|
package/README.md
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
# Antigravity Token Collector
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Collect donated Antigravity tokens from anyone and sync them into your [9Router](https://github.com/decolua/9router) database.**
|
|
8
|
+
|
|
9
|
+
English | [Bahasa Indonesia](README.id.md) (Tersedia dalam 2 Bahasa / Available in 2 Languages)
|
|
8
10
|
|
|
9
11
|
[](https://www.npmjs.com/package/antigravity-tc)
|
|
10
12
|
[](LICENSE)
|
|
11
|
-
[](#-
|
|
13
|
+
[](#-platform-support)
|
|
12
14
|
[]()
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
A tray app and dashboard for managing donated Antigravity tokens: customizable public portal, multilingual copy, free public tunnel, login auto-start, eligibility checks, and two-way 9Router sync.
|
|
15
17
|
|
|
16
18
|
</div>
|
|
17
19
|
|
|
@@ -24,112 +26,121 @@ npm install -g antigravity-tc
|
|
|
24
26
|
antigravity-tc
|
|
25
27
|
```
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
__That's it!__ 🚀
|
|
29
|
+
The dashboard opens at `http://localhost:3456/dashboard`, and the tray icon appears in your menu bar/system tray.
|
|
30
30
|
|
|
31
|
-
>
|
|
31
|
+
> Default password: `1234567890`. Change it immediately in **Settings → Security**.
|
|
32
32
|
>
|
|
33
|
-
>
|
|
34
|
-
|
|
35
|
-
## 🔄 Cara Kerja
|
|
33
|
+
> Forgot your password? Run `antigravity-tc-reset-password`.
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
┌──────────────────┐ ┌─────────────────────┐ ┌──────────────────┐
|
|
39
|
-
│ Donatur │ │ ATC (Anda) │ │ 9Router │
|
|
40
|
-
│ │ │ │ │ │
|
|
41
|
-
│ Login Google ───┼──────▶ │ Cek eligibility ───┼──────▶ │ Token tersimpan │
|
|
42
|
-
│ lewat link yang │ │ Refresh otomatis │ │ siap dipakai │
|
|
43
|
-
│ Anda bagikan │ │ Anti-duplikat │ │ │
|
|
44
|
-
└──────────────────┘ └─────────────────────┘ └──────────────────┘
|
|
45
|
-
```
|
|
35
|
+
## 🔄 How It Works
|
|
46
36
|
|
|
47
|
-
1.
|
|
48
|
-
2.
|
|
49
|
-
3.
|
|
37
|
+
1. Run `antigravity-tc`.
|
|
38
|
+
2. Generate a personal donation link from the dashboard, or enable the public tunnel.
|
|
39
|
+
3. Donors sign in with Google and paste the Antigravity code.
|
|
40
|
+
4. ATC checks eligibility, refreshes tokens when needed, and stores donation logs locally.
|
|
41
|
+
5. Sync eligible tokens into 9Router when you are ready.
|
|
42
|
+
6. Customize the public portal wording and layout from **Settings → Portal Settings**.
|
|
50
43
|
|
|
51
|
-
## 🖼️
|
|
44
|
+
## 🖼️ Screenshots
|
|
52
45
|
|
|
53
|
-
| Dashboard | Sync
|
|
46
|
+
| Dashboard | Bulk Sync | Settings |
|
|
54
47
|
| :---: | :---: | :---: |
|
|
55
|
-
|  |  |  |  |  |
|
|
56
49
|
|
|
57
|
-
## 📋
|
|
50
|
+
## 📋 Features
|
|
58
51
|
|
|
59
|
-
|
|
|
52
|
+
| Feature | Description |
|
|
60
53
|
| --- | --- |
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
54
|
+
| Public donation portal | Google login + manual code paste flow for donors |
|
|
55
|
+
| Portal Settings | Customize layout and front-page wording; stored in ATC app config, not 9Router DB |
|
|
56
|
+
| Multilingual support | Fully localized dashboard and portal in English and Bahasa Indonesia |
|
|
57
|
+
| Personal donation links | `?for=Name` automatically customizes the greeting |
|
|
58
|
+
| Admin dashboard | Stats, live table, search, status/source/tier filters, CSV import/export |
|
|
59
|
+
| Tier Detection & Filter | Displays donor tier (**Free**, **Plus**, **Pro**, **Ultra**) with quick filters |
|
|
60
|
+
| Go Keyring Export | Export donor token as `go-keyring-base64` to force login into official Antigravity apps |
|
|
61
|
+
| Sync to 9Router | Upsert local donation logs into 9Router `providerConnections` |
|
|
62
|
+
| Sync from 9Router | Import 9Router `providerConnections` back into local donation logs |
|
|
63
|
+
| Check ALL Eligibility | Check all token rows with per-row delay and status recap |
|
|
64
|
+
| Token refresh | Expired access tokens are refreshed before eligibility checks when possible |
|
|
65
|
+
| Free public tunnel | Cloudflare Quick Tunnel gives you a public URL without exposing your IP |
|
|
66
|
+
| Restart Services | Restart from tray or Settings after config changes such as 9Router DB path |
|
|
67
|
+
| Auto-start | Launches in tray mode when the OS starts |
|
|
68
|
+
| Security | JWT admin login, per-install secret, tunnel blocked while default password is active |
|
|
69
|
+
|
|
70
|
+
## 🚀 Log in to Official Apps (Antigravity & antigravity-cli)
|
|
71
|
+
|
|
72
|
+
You can use donated tokens to authenticate directly into the official **Antigravity** app or **antigravity-cli** without going through browser OAuth:
|
|
73
|
+
|
|
74
|
+
1. In the admin donation table, click the action menu (**...**) for any donor → select **Go Keyring**.
|
|
75
|
+
2. Copy the `go-keyring-base64:...` string or use the provided one-click terminal commands:
|
|
76
|
+
- **macOS (Keychain)**:
|
|
77
|
+
```bash
|
|
78
|
+
security add-generic-password -s gemini -a antigravity -w "<KEYRING_STRING>" -U
|
|
79
|
+
```
|
|
80
|
+
- **Windows (CMD / PowerShell)**:
|
|
81
|
+
```powershell
|
|
82
|
+
cmdkey /generic:"gemini:antigravity" /user:"antigravity" /pass:"<KEYRING_STRING>"
|
|
83
|
+
```
|
|
84
|
+
*(Or manually add under **Windows Credential Manager** → Generic Credentials).*
|
|
85
|
+
3. Launch Antigravity or execute `antigravity-cli` — the donor session will be active immediately.
|
|
86
|
+
|
|
87
|
+
## 📁 Data Locations
|
|
88
|
+
|
|
89
|
+
### 9Router database
|
|
90
|
+
|
|
91
|
+
| OS | Default path |
|
|
77
92
|
| --- | --- |
|
|
78
93
|
| macOS / Linux | `~/.9router/db/data.sqlite` |
|
|
79
94
|
| Windows | `%APPDATA%/9router/db/data.sqlite` |
|
|
80
|
-
| Docker | `/app/data/db/data.sqlite`
|
|
95
|
+
| Docker | `/app/data/db/data.sqlite` |
|
|
81
96
|
|
|
82
|
-
|
|
97
|
+
You can override this path from **Dashboard → Settings → 9Router Database** or by setting `DB_PATH`. Restart services after changing it.
|
|
83
98
|
|
|
84
|
-
###
|
|
99
|
+
### ATC app data
|
|
85
100
|
|
|
86
|
-
| OS |
|
|
101
|
+
| OS | Path |
|
|
87
102
|
| --- | --- |
|
|
88
103
|
| macOS / Linux | `~/.antigravity-tc/` |
|
|
89
104
|
| Windows | `%USERPROFILE%\.antigravity-tc\` |
|
|
90
|
-
| Docker | `/root/.antigravity-tc/`
|
|
105
|
+
| Docker | `/root/.antigravity-tc/` |
|
|
91
106
|
|
|
92
|
-
|
|
|
107
|
+
| Content | Description |
|
|
93
108
|
| --- | --- |
|
|
94
|
-
| `.env` |
|
|
95
|
-
| `logs/donation-logs.sqlite` |
|
|
96
|
-
| `bin/cloudflared` |
|
|
97
|
-
|
|
|
109
|
+
| `.env` | Local environment configuration |
|
|
110
|
+
| `logs/donation-logs.sqlite` | Donation log database |
|
|
111
|
+
| `bin/cloudflared` | Downloaded tunnel binary |
|
|
112
|
+
| App config | Admin password, portal settings, language, auto-start, 9Router DB path |
|
|
98
113
|
|
|
99
|
-
## 🖥️
|
|
114
|
+
## 🖥️ Platform Support
|
|
100
115
|
|
|
101
|
-
|
|
|
116
|
+
| Capability | macOS | Linux | Windows | Docker |
|
|
102
117
|
| --- | :---: | :---: | :---: | :---: |
|
|
103
|
-
| Server +
|
|
118
|
+
| Server + dashboard + public portal | ✅ | ✅ | ✅ | ✅ |
|
|
104
119
|
| Tray icon | ✅ | ✅ | ✅ | — |
|
|
105
|
-
|
|
|
120
|
+
| Login auto-start | ✅ | ✅ | ✅ | — |
|
|
106
121
|
| Cloudflare Tunnel | ✅ | ✅ | ✅ | ✅ |
|
|
107
|
-
|
|
|
108
|
-
|
|
109
|
-
> Docker: jalankan dengan `antigravity-tc --hidden` sebagai entrypoint dan mount volume data (lihat tabel di atas). Deteksi Docker otomatis memakai path `/app/data/db/data.sqlite`.
|
|
122
|
+
| Automatic 9Router DB path detection | ✅ | ✅ | ✅ | ✅ |
|
|
110
123
|
|
|
111
124
|
## 🔑 Password & `.env`
|
|
112
125
|
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
126
|
+
- Default password: `1234567890`.
|
|
127
|
+
- Password priority: dashboard setting > `APP_PASSWORD` > default.
|
|
128
|
+
- The public Antigravity CLI OAuth credentials are bundled by default.
|
|
129
|
+
- You can still override `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` if needed.
|
|
116
130
|
|
|
117
131
|
## ❓ Troubleshooting
|
|
118
132
|
|
|
119
|
-
|
|
|
133
|
+
| Problem | Fix |
|
|
120
134
|
| --- | --- |
|
|
121
|
-
|
|
|
122
|
-
| Tunnel
|
|
123
|
-
| Tray icon
|
|
124
|
-
|
|
|
125
|
-
| Refresh token
|
|
126
|
-
| DB 9Router tidak ketemu | Cek path di Pengaturan → Database 9Router |
|
|
127
|
-
|
|
128
|
-
---
|
|
135
|
+
| Forgot admin password | Run `antigravity-tc-reset-password` |
|
|
136
|
+
| Tunnel cannot be enabled | Change the default password first |
|
|
137
|
+
| Tray icon missing | Make sure the `systray2/traybin/` binary is executable |
|
|
138
|
+
| 9Router DB not found | Check Settings → 9Router Database, then restart services |
|
|
139
|
+
| Refresh token fails | The donor may need to sign in again if Google rejects the refresh token |
|
|
129
140
|
|
|
130
141
|
## 🛠️ Development
|
|
131
142
|
|
|
132
|
-
|
|
143
|
+
See [dev.md](dev.md) and [build.md](build.md).
|
|
133
144
|
|
|
134
145
|
## 📄 License
|
|
135
146
|
|
package/bin/restart.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { execSync, spawn } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const { ensureEnvFile } = require('../src/paths');
|
|
8
|
+
require('dotenv').config({ path: ensureEnvFile(), quiet: true });
|
|
9
|
+
const { getConfig } = require('../src/config');
|
|
10
|
+
|
|
11
|
+
const config = getConfig();
|
|
12
|
+
const port = Number(process.env.PORT || config.get('port') || 3456);
|
|
13
|
+
const LOCK_FILE_PATH = path.join(os.tmpdir(), 'antigravity-token-collector.lock');
|
|
14
|
+
|
|
15
|
+
function isPidAlive(pid) {
|
|
16
|
+
try {
|
|
17
|
+
process.kill(pid, 0);
|
|
18
|
+
return true;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function findRunningPids() {
|
|
25
|
+
const pids = new Set();
|
|
26
|
+
|
|
27
|
+
// 1. Cek via lsof (port listener)
|
|
28
|
+
if (process.platform !== 'win32') {
|
|
29
|
+
try {
|
|
30
|
+
const lsofOut = execSync(`lsof -ti :${port}`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
31
|
+
if (lsofOut) {
|
|
32
|
+
for (const line of lsofOut.split('\n')) {
|
|
33
|
+
const pid = parseInt(line.trim(), 10);
|
|
34
|
+
if (pid && pid !== process.pid) pids.add(pid);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch (e) {}
|
|
38
|
+
|
|
39
|
+
// 2. Cek via ps untuk proses node yang menjalankan index.js
|
|
40
|
+
try {
|
|
41
|
+
const psOut = execSync('ps -eo pid,command', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
42
|
+
for (const line of psOut.split('\n')) {
|
|
43
|
+
if (line.includes('index.js') && (line.includes('antigravity-tc') || line.includes('antigravity-token-collector'))) {
|
|
44
|
+
const match = line.trim().match(/^(\d+)/);
|
|
45
|
+
if (match) {
|
|
46
|
+
const pid = parseInt(match[1], 10);
|
|
47
|
+
if (pid && pid !== process.pid) pids.add(pid);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {}
|
|
52
|
+
} else {
|
|
53
|
+
// Windows fallback
|
|
54
|
+
try {
|
|
55
|
+
const netstatOut = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
56
|
+
for (const line of netstatOut.split('\n')) {
|
|
57
|
+
const parts = line.trim().split(/\s+/);
|
|
58
|
+
const pid = parseInt(parts[parts.length - 1], 10);
|
|
59
|
+
if (pid && pid !== process.pid) pids.add(pid);
|
|
60
|
+
}
|
|
61
|
+
} catch (e) {}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return Array.from(pids);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function stopRunningInstances() {
|
|
68
|
+
const pids = findRunningPids();
|
|
69
|
+
if (!pids.length) {
|
|
70
|
+
console.log('ℹ️ Tidak ada instance Antigravity-tc yang sedang aktif.');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`🔄 Menghentikan instance Antigravity-tc yang sedang berjalan (PID: ${pids.join(', ')})...`);
|
|
75
|
+
|
|
76
|
+
for (const pid of pids) {
|
|
77
|
+
try {
|
|
78
|
+
process.kill(pid, 'SIGTERM');
|
|
79
|
+
} catch (e) {}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Tunggu hingga proses benar-benar berhenti
|
|
83
|
+
const deadline = Date.now() + 2500;
|
|
84
|
+
while (Date.now() < deadline) {
|
|
85
|
+
const alive = pids.filter(isPidAlive);
|
|
86
|
+
if (!alive.length) break;
|
|
87
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Force kill jika masih hidup
|
|
91
|
+
for (const pid of pids) {
|
|
92
|
+
if (isPidAlive(pid)) {
|
|
93
|
+
try {
|
|
94
|
+
process.kill(pid, 'SIGKILL');
|
|
95
|
+
} catch (e) {}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Bersihkan stale lock file bila ada
|
|
100
|
+
try {
|
|
101
|
+
if (fs.existsSync(LOCK_FILE_PATH)) fs.unlinkSync(LOCK_FILE_PATH);
|
|
102
|
+
const lockDir = `${LOCK_FILE_PATH}.lock`;
|
|
103
|
+
if (fs.existsSync(lockDir)) fs.rmSync(lockDir, { recursive: true, force: true });
|
|
104
|
+
} catch (e) {}
|
|
105
|
+
|
|
106
|
+
console.log('✅ Instance lama berhasil dihentikan.');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function main() {
|
|
110
|
+
await stopRunningInstances();
|
|
111
|
+
|
|
112
|
+
// Beri jeda sejenak agar OS melepaskan socket port sepenuhnya
|
|
113
|
+
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
114
|
+
|
|
115
|
+
console.log('🚀 Memulai ulang Antigravity Token Collector...');
|
|
116
|
+
|
|
117
|
+
const indexPath = path.join(__dirname, '..', 'index.js');
|
|
118
|
+
const args = process.argv.slice(2);
|
|
119
|
+
const child = spawn(process.execPath, [indexPath, ...args], {
|
|
120
|
+
cwd: path.join(__dirname, '..'),
|
|
121
|
+
stdio: 'inherit',
|
|
122
|
+
env: process.env,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
child.on('exit', (code) => {
|
|
126
|
+
process.exit(code || 0);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
main().catch((err) => {
|
|
131
|
+
console.error('❌ Gagal merestart aplikasi:', err);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
});
|
package/build.md
CHANGED
|
@@ -35,6 +35,8 @@ web/dist/
|
|
|
35
35
|
npm version major # 1.0.0 → 2.0.0 (breaking change)
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
> **Tips**: Jika git working tree belum di-commit, gunakan flag `--no-git-tag-version`, misal: `npm version 1.1.4 --no-git-tag-version`.
|
|
39
|
+
|
|
38
40
|
3. **Lint bersih**: `npm run lint`
|
|
39
41
|
4. **Verifikasi isi paket** (yang penting — pastikan secret tidak ikut):
|
|
40
42
|
|
package/index.js
CHANGED
|
@@ -30,6 +30,7 @@ let releaseLock = null;
|
|
|
30
30
|
let trayManager = null;
|
|
31
31
|
let menuOpen = false;
|
|
32
32
|
let isHandoffInProgress = false;
|
|
33
|
+
let isRestartInProgress = false;
|
|
33
34
|
|
|
34
35
|
async function acquireSingleInstanceLock() {
|
|
35
36
|
if (!fs.existsSync(LOCK_FILE_PATH)) {
|
|
@@ -47,7 +48,7 @@ async function acquireSingleInstanceLock() {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
async function
|
|
51
|
+
async function prepareShutdown() {
|
|
51
52
|
try {
|
|
52
53
|
const tunnelManager = getTunnelManager();
|
|
53
54
|
if (tunnelManager) {
|
|
@@ -65,7 +66,13 @@ async function cleanupAndExit(exitCode = 0) {
|
|
|
65
66
|
|
|
66
67
|
try {
|
|
67
68
|
if (server.listening) {
|
|
68
|
-
await new Promise((resolve) =>
|
|
69
|
+
await new Promise((resolve) => {
|
|
70
|
+
const timer = setTimeout(() => resolve(), 300);
|
|
71
|
+
server.close(() => {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
resolve();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
69
76
|
}
|
|
70
77
|
} catch (error) {}
|
|
71
78
|
|
|
@@ -75,10 +82,40 @@ async function cleanupAndExit(exitCode = 0) {
|
|
|
75
82
|
releaseLock = null;
|
|
76
83
|
}
|
|
77
84
|
} catch (error) {}
|
|
85
|
+
}
|
|
78
86
|
|
|
87
|
+
async function cleanupAndExit(exitCode = 0) {
|
|
88
|
+
await prepareShutdown();
|
|
79
89
|
process.exit(exitCode);
|
|
80
90
|
}
|
|
81
91
|
|
|
92
|
+
async function restartServices(port = configuredPort) {
|
|
93
|
+
if (isRestartInProgress) return;
|
|
94
|
+
isRestartInProgress = true;
|
|
95
|
+
await prepareShutdown();
|
|
96
|
+
|
|
97
|
+
// Beri jeda kecil agar OS melepaskan lock file sepenuhnya
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
99
|
+
|
|
100
|
+
const logFile = '/tmp/antigravity-tc-restart.log';
|
|
101
|
+
const out = fs.openSync(logFile, 'a');
|
|
102
|
+
const err = fs.openSync(logFile, 'a');
|
|
103
|
+
|
|
104
|
+
fs.writeSync(out, `\n--- RESTART SPARKED AT ${new Date().toISOString()} ---\n`);
|
|
105
|
+
|
|
106
|
+
const child = spawn(process.execPath, [path.join(__dirname, 'index.js'), '--hidden'], {
|
|
107
|
+
cwd: process.cwd(),
|
|
108
|
+
detached: true,
|
|
109
|
+
stdio: ['ignore', out, err],
|
|
110
|
+
env: {
|
|
111
|
+
...process.env,
|
|
112
|
+
PORT: String(port),
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
child.unref();
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
82
119
|
async function releaseInstanceLock() {
|
|
83
120
|
if (!releaseLock) return;
|
|
84
121
|
try {
|
|
@@ -144,6 +181,7 @@ async function main() {
|
|
|
144
181
|
trayManager = new TrayManager({ config, port });
|
|
145
182
|
await trayManager.start();
|
|
146
183
|
trayManager.on('exit', () => cleanupAndExit(0));
|
|
184
|
+
trayManager.on('restart', () => restartServices(port));
|
|
147
185
|
|
|
148
186
|
const menuContext = {
|
|
149
187
|
trayManager,
|
|
@@ -158,6 +196,10 @@ async function main() {
|
|
|
158
196
|
}
|
|
159
197
|
}
|
|
160
198
|
|
|
199
|
+
process.on('antigravity-restart', () => {
|
|
200
|
+
restartServices(configuredPort);
|
|
201
|
+
});
|
|
202
|
+
|
|
161
203
|
process.on('SIGINT', () => {
|
|
162
204
|
cleanupAndExit(0);
|
|
163
205
|
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antigravity-tc",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Antigravity Token Collector — tray app untuk mengumpulkan & mengelola donasi token Antigravity ke 9Router",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"antigravity-tc": "./index.js",
|
|
8
|
-
"antigravity-tc-reset-password": "./bin/reset-password.js"
|
|
8
|
+
"antigravity-tc-reset-password": "./bin/reset-password.js",
|
|
9
|
+
"antigravity-tc-restart": "./bin/restart.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"index.js",
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
"build:web": "vite build --config web/vite.config.mjs",
|
|
25
26
|
"lint": "eslint .",
|
|
26
27
|
"prepublishOnly": "npm run lint && npm run build:web",
|
|
27
|
-
"start": "node index.js"
|
|
28
|
+
"start": "node index.js",
|
|
29
|
+
"restart": "node bin/restart.js"
|
|
28
30
|
},
|
|
29
31
|
"keywords": [
|
|
30
32
|
"antigravity",
|