lazy-gravity 0.0.2 → 0.0.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/LICENSE +21 -0
- package/README.md +224 -0
- package/dist/bin/cli.js +79 -0
- package/dist/bin/commands/doctor.js +156 -0
- package/dist/bin/commands/open.js +145 -0
- package/dist/bin/commands/setup.js +366 -0
- package/dist/bin/commands/start.js +15 -0
- package/dist/bot/index.js +914 -0
- package/dist/commands/chatCommandHandler.js +145 -0
- package/dist/commands/cleanupCommandHandler.js +396 -0
- package/dist/commands/messageParser.js +28 -0
- package/dist/commands/registerSlashCommands.js +149 -0
- package/dist/commands/slashCommandHandler.js +104 -0
- package/dist/commands/workspaceCommandHandler.js +230 -0
- package/dist/database/chatSessionRepository.js +88 -0
- package/dist/database/scheduleRepository.js +119 -0
- package/dist/database/templateRepository.js +103 -0
- package/dist/database/workspaceBindingRepository.js +109 -0
- package/dist/events/interactionCreateHandler.js +286 -0
- package/dist/events/messageCreateHandler.js +154 -0
- package/dist/index.js +10 -0
- package/dist/middleware/auth.js +10 -0
- package/dist/middleware/sanitize.js +20 -0
- package/dist/services/antigravityLauncher.js +89 -0
- package/dist/services/approvalDetector.js +384 -0
- package/dist/services/autoAcceptService.js +80 -0
- package/dist/services/cdpBridgeManager.js +204 -0
- package/dist/services/cdpConnectionPool.js +157 -0
- package/dist/services/cdpService.js +1311 -0
- package/dist/services/channelManager.js +118 -0
- package/dist/services/chatSessionService.js +516 -0
- package/dist/services/modeService.js +73 -0
- package/dist/services/modelService.js +63 -0
- package/dist/services/processManager.js +61 -0
- package/dist/services/progressSender.js +61 -0
- package/dist/services/promptDispatcher.js +17 -0
- package/dist/services/quotaService.js +185 -0
- package/dist/services/responseMonitor.js +645 -0
- package/dist/services/scheduleService.js +134 -0
- package/dist/services/screenshotService.js +85 -0
- package/dist/services/titleGeneratorService.js +113 -0
- package/dist/services/workspaceService.js +64 -0
- package/dist/ui/autoAcceptUi.js +34 -0
- package/dist/ui/modeUi.js +34 -0
- package/dist/ui/modelsUi.js +97 -0
- package/dist/ui/screenshotUi.js +51 -0
- package/dist/ui/templateUi.js +67 -0
- package/dist/utils/cdpPorts.js +5 -0
- package/dist/utils/config.js +20 -0
- package/dist/utils/configLoader.js +160 -0
- package/dist/utils/discordFormatter.js +167 -0
- package/dist/utils/i18n.js +77 -0
- package/dist/utils/imageHandler.js +154 -0
- package/dist/utils/lockfile.js +113 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logo.js +13 -0
- package/dist/utils/metadataExtractor.js +15 -0
- package/dist/utils/processLogBuffer.js +98 -0
- package/dist/utils/streamMessageFormatter.js +90 -0
- package/package.json +73 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LazyGravity Project
|
|
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
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/tokyoweb3/LazyGravity/main/docs/assets/LazyGravityBanner.png" alt="LazyGravity Banner" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://img.shields.io/badge/version-0.0.1-blue?style=flat-square" alt="Version" />
|
|
7
|
+
<img src="https://img.shields.io/badge/node-18.x+-brightgreen?style=flat-square&logo=node.js" alt="Node.js" />
|
|
8
|
+
<img src="https://img.shields.io/badge/discord.js-14.x-5865F2?style=flat-square&logo=discord&logoColor=white" alt="discord.js" />
|
|
9
|
+
<img src="https://img.shields.io/badge/protocol-CDP%20%2F%20WebSocket-orange?style=flat-square" alt="CDP/WebSocket" />
|
|
10
|
+
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License" />
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
# LazyGravity
|
|
14
|
+
|
|
15
|
+
**LazyGravity** is a local, secure Discord Bot that lets you remotely operate [Antigravity](https://antigravity.dev) on your home PC — from your smartphone's Discord app, anywhere.
|
|
16
|
+
|
|
17
|
+
Send natural language instructions like "fix that bug" or "start designing the new feature" from your phone. Antigravity executes them locally on your home PC using its full resources, and reports results back to Discord.
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<video src="https://github.com/user-attachments/assets/84eca973-59e8-4ffa-93e9-fba78ba72f74" width="100%" controls autoplay muted loop>
|
|
21
|
+
Your browser does not support the video tag.
|
|
22
|
+
</video>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Quick Setup
|
|
27
|
+
|
|
28
|
+
Runtime: **Node >= 18**.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g lazy-gravity
|
|
32
|
+
lazy-gravity setup
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The interactive wizard walks you through Discord bot creation, token setup, and workspace configuration. When done:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
lazy-gravity open # Launch Antigravity with CDP enabled
|
|
39
|
+
lazy-gravity start # Start the Discord bot
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or run directly without installing:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx lazy-gravity
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
1. **Fully Local & Secure**
|
|
53
|
+
- **No external server or port exposure** — runs as a local process on your PC, communicating directly with Discord.
|
|
54
|
+
- **Whitelist access control**: only authorized Discord user IDs (`allowedUserIds`) can interact with the bot.
|
|
55
|
+
- **Secure credential management**: Bot tokens and API keys are stored locally (never in source code).
|
|
56
|
+
- **Path traversal prevention & resource protection**: sandboxed directory access and concurrent task limits prevent abuse.
|
|
57
|
+
|
|
58
|
+
2. **Project Management (Channel-Directory Binding)**
|
|
59
|
+
- Use `/project` to bind a Discord channel to a local project directory via an interactive select menu with buttons.
|
|
60
|
+
- Messages sent in a bound channel are automatically forwarded to Antigravity with the correct project context.
|
|
61
|
+
|
|
62
|
+
3. **Context-Aware Embed Replies**
|
|
63
|
+
- Results are delivered as rich Discord Embeds. Use Discord's Reply feature on any result to continue the conversation — the bot preserves full context (directory, task history) across reply chains.
|
|
64
|
+
|
|
65
|
+
4. **Real-Time Progress Monitoring**
|
|
66
|
+
- Long-running Antigravity tasks report progress as a series of messages (delivery confirmed / planning / analysis / execution / implementation / final summary).
|
|
67
|
+
|
|
68
|
+
5. **File Attachments & Context Parsing**
|
|
69
|
+
- Send images (screenshots, mockups) or text files via Discord — they are automatically forwarded to Antigravity as context.
|
|
70
|
+
|
|
71
|
+
## Usage & Commands
|
|
72
|
+
|
|
73
|
+
### Natural Language Messages
|
|
74
|
+
Just type in any bound channel:
|
|
75
|
+
> `refactor the components under src/components. Make the layout look like yesterday's screenshot` (with image attached)
|
|
76
|
+
|
|
77
|
+
### Slash Commands
|
|
78
|
+
|
|
79
|
+
- `📂 /project list` — Browse projects via select menu; selecting one auto-creates a category and session channel
|
|
80
|
+
- `📂 /project create <name>` — Create a new project directory + Discord category/channel
|
|
81
|
+
- `💬 /new` — Start a new Antigravity chat session in the current project
|
|
82
|
+
- `💬 /chat` — Show current session info and list all sessions in the project
|
|
83
|
+
- `⚙️ /model [name]` — Switch the LLM model (e.g. `gpt-4o`, `claude-3-opus`, `gemini-1.5-pro`)
|
|
84
|
+
- `⚙️ /mode` — Switch execution mode via dropdown (`code`, `architect`, `ask`, etc.)
|
|
85
|
+
- `📝 /template list` — Display registered templates with execute buttons
|
|
86
|
+
- `📝 /template add <name> <prompt>` — Register a new prompt template
|
|
87
|
+
- `📝 /template delete <name>` — Delete a template
|
|
88
|
+
- `🛑 /stop` — Force-stop a running Antigravity task
|
|
89
|
+
- `📸 /screenshot` — Capture and send Antigravity's current screen
|
|
90
|
+
- `🔧 /status` — Show bot connection status, current mode, and active project
|
|
91
|
+
- `✅ /autoaccept [on|off|status]` — Toggle auto-approval of file edit dialogs
|
|
92
|
+
- `🧹 /cleanup [days]` — Scan and clean up inactive session channels (default: 7 days)
|
|
93
|
+
- `❓ /help` — Display list of available commands
|
|
94
|
+
|
|
95
|
+
### CLI Commands
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
lazy-gravity # Auto: runs setup if unconfigured, otherwise starts the bot
|
|
99
|
+
lazy-gravity setup # Interactive setup wizard
|
|
100
|
+
lazy-gravity open # Open Antigravity with CDP (auto-selects available port)
|
|
101
|
+
lazy-gravity start # Start the Discord bot
|
|
102
|
+
lazy-gravity doctor # Check environment and dependencies
|
|
103
|
+
lazy-gravity --version # Show version
|
|
104
|
+
lazy-gravity --help # Show help
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Setup (Detailed)
|
|
110
|
+
|
|
111
|
+
### Option A: npm (Recommended)
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm install -g lazy-gravity
|
|
115
|
+
lazy-gravity setup
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The wizard guides you through 4 steps:
|
|
119
|
+
|
|
120
|
+
1. **Discord Bot Token** — create a bot at the [Discord Developer Portal](https://discord.com/developers/applications), enable Privileged Gateway Intents (PRESENCE, SERVER MEMBERS, MESSAGE CONTENT), and copy the token. Client ID is extracted from the token automatically.
|
|
121
|
+
2. **Guild (Server) ID** — for instant slash command registration (optional; press Enter to skip).
|
|
122
|
+
3. **Allowed User IDs** — Discord users authorized to interact with the bot.
|
|
123
|
+
4. **Workspace Directory** — parent directory where your coding projects live.
|
|
124
|
+
|
|
125
|
+
Config is saved to `~/.lazy-gravity/config.json`.
|
|
126
|
+
|
|
127
|
+
### Option B: From source
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
git clone https://github.com/tokyoweb3/LazyGravity.git
|
|
131
|
+
cd LazyGravity
|
|
132
|
+
npm install
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Set up your `.env` file:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
cp .env.example .env
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Edit `.env` and fill in the required values:
|
|
142
|
+
|
|
143
|
+
```env
|
|
144
|
+
DISCORD_BOT_TOKEN=your_bot_token_here
|
|
145
|
+
GUILD_ID=your_guild_id_here
|
|
146
|
+
ALLOWED_USER_IDS=123456789,987654321
|
|
147
|
+
WORKSPACE_BASE_DIR=~/Code
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Then start the bot:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm run start
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Alternatively, you can build and use the CLI:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm run build
|
|
160
|
+
node dist/bin/cli.js setup # or: node dist/bin/cli.js start
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Launch Antigravity with CDP
|
|
164
|
+
|
|
165
|
+
LazyGravity connects to Antigravity via Chrome DevTools Protocol (CDP).
|
|
166
|
+
You need to launch Antigravity with a remote debugging port enabled.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Easiest way (auto-selects an available port):
|
|
170
|
+
lazy-gravity open
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
If you cloned from source, you can also use the bundled launcher scripts (they auto-detect an available port from 9222–9666):
|
|
174
|
+
|
|
175
|
+
#### macOS
|
|
176
|
+
Double-click **`start_antigravity_mac.command`** in the repo root.
|
|
177
|
+
|
|
178
|
+
- **First run**: if you get a permission error, run `chmod +x start_antigravity_mac.command` once in the terminal.
|
|
179
|
+
|
|
180
|
+
#### Windows
|
|
181
|
+
Double-click **`start_antigravity_win.bat`** in the repo root.
|
|
182
|
+
|
|
183
|
+
- **If it doesn't launch**: the executable may not be in your PATH. Right-click the file, edit it, and replace `"Antigravity.exe"` with the full install path (e.g. `"%LOCALAPPDATA%\Programs\Antigravity\Antigravity.exe"`).
|
|
184
|
+
|
|
185
|
+
> **Tip**: CDP ports are auto-scanned from candidates (9222, 9223, 9333, 9444, 9555, 9666).
|
|
186
|
+
> Launch Antigravity first, then start the bot — it connects automatically.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Troubleshooting
|
|
191
|
+
|
|
192
|
+
If the bot is unresponsive or you've updated the code, restart it:
|
|
193
|
+
|
|
194
|
+
1. **Stop the bot** — press `Ctrl + C` in the terminal, or:
|
|
195
|
+
```bash
|
|
196
|
+
pkill -f "lazy-gravity"
|
|
197
|
+
```
|
|
198
|
+
2. **Restart**
|
|
199
|
+
```bash
|
|
200
|
+
lazy-gravity start
|
|
201
|
+
# or, from source: npm run start
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
If Antigravity is restarted, the bot automatically attempts CDP reconnection. Sending a message triggers automatic project reconnection.
|
|
205
|
+
|
|
206
|
+
Run `lazy-gravity doctor` to diagnose configuration and connectivity issues.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## How CDP Connection Works
|
|
211
|
+
|
|
212
|
+
<p align="center">
|
|
213
|
+
<img src="https://raw.githubusercontent.com/tokyoweb3/LazyGravity/main/docs/images/architecture.svg" alt="LazyGravity Architecture" width="100%" />
|
|
214
|
+
</p>
|
|
215
|
+
|
|
216
|
+
1. The bot scans debug ports (default: 9222) and auto-detects the Antigravity target
|
|
217
|
+
2. Connects via WebSocket to CDP (`Runtime.evaluate` for DOM operations)
|
|
218
|
+
3. Injects messages into the chat input, monitors Antigravity responses, and captures screenshots
|
|
219
|
+
|
|
220
|
+
**On disconnect**: automatically retries up to 3 times (`maxReconnectAttempts`). If all retries fail, an error notification is sent to Discord.
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
[MIT](LICENSE)
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const commander_1 = require("commander");
|
|
40
|
+
const package_json_1 = require("../../package.json");
|
|
41
|
+
const start_1 = require("./commands/start");
|
|
42
|
+
const doctor_1 = require("./commands/doctor");
|
|
43
|
+
const setup_1 = require("./commands/setup");
|
|
44
|
+
const open_1 = require("./commands/open");
|
|
45
|
+
const configLoader_1 = require("../utils/configLoader");
|
|
46
|
+
let commandRan = false;
|
|
47
|
+
const markRan = (fn) => ((...args) => { commandRan = true; return fn(...args); });
|
|
48
|
+
const program = new commander_1.Command()
|
|
49
|
+
.name('lazy-gravity')
|
|
50
|
+
.description('Control your AI coding assistant from Discord')
|
|
51
|
+
.version(package_json_1.version);
|
|
52
|
+
program
|
|
53
|
+
.command('start')
|
|
54
|
+
.description('Start the Discord bot')
|
|
55
|
+
.action(markRan(start_1.startAction));
|
|
56
|
+
program
|
|
57
|
+
.command('doctor')
|
|
58
|
+
.description('Check environment and dependencies')
|
|
59
|
+
.action(markRan(doctor_1.doctorAction));
|
|
60
|
+
program
|
|
61
|
+
.command('setup')
|
|
62
|
+
.description('Interactive setup wizard')
|
|
63
|
+
.action(markRan(setup_1.setupAction));
|
|
64
|
+
program
|
|
65
|
+
.command('open')
|
|
66
|
+
.description('Open Antigravity with CDP enabled (auto-selects available port)')
|
|
67
|
+
.action(markRan(open_1.openAction));
|
|
68
|
+
program.parse();
|
|
69
|
+
// Default behavior: if no subcommand was matched, decide what to run
|
|
70
|
+
if (!commandRan) {
|
|
71
|
+
const hasConfig = configLoader_1.ConfigLoader.configExists();
|
|
72
|
+
const hasEnv = fs.existsSync(path.resolve(process.cwd(), '.env'));
|
|
73
|
+
if (!hasConfig && !hasEnv) {
|
|
74
|
+
(0, setup_1.setupAction)();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
(0, start_1.startAction)();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.doctorAction = doctorAction;
|
|
37
|
+
const http = __importStar(require("http"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const cdpPorts_1 = require("../../utils/cdpPorts");
|
|
41
|
+
const configLoader_1 = require("../../utils/configLoader");
|
|
42
|
+
function checkPort(port) {
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
const req = http.get(`http://127.0.0.1:${port}/json/list`, (res) => {
|
|
45
|
+
let data = '';
|
|
46
|
+
res.on('data', (chunk) => (data += chunk));
|
|
47
|
+
res.on('end', () => {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(data);
|
|
50
|
+
resolve(Array.isArray(parsed));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
resolve(false);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
req.on('error', () => resolve(false));
|
|
58
|
+
req.setTimeout(2000, () => {
|
|
59
|
+
req.destroy();
|
|
60
|
+
resolve(false);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function checkEnvFile() {
|
|
65
|
+
const envPath = path.resolve(process.cwd(), '.env');
|
|
66
|
+
return { exists: fs.existsSync(envPath), path: envPath };
|
|
67
|
+
}
|
|
68
|
+
function checkRequiredEnvVars() {
|
|
69
|
+
const required = ['DISCORD_BOT_TOKEN', 'CLIENT_ID', 'ALLOWED_USER_IDS'];
|
|
70
|
+
return required.map((name) => ({
|
|
71
|
+
name,
|
|
72
|
+
set: Boolean(process.env[name]),
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
async function doctorAction() {
|
|
76
|
+
console.log('lazy-gravity doctor\n');
|
|
77
|
+
let allOk = true;
|
|
78
|
+
// 1. Config directory check
|
|
79
|
+
const configDir = configLoader_1.ConfigLoader.getConfigDir();
|
|
80
|
+
if (fs.existsSync(configDir)) {
|
|
81
|
+
console.log(` [OK] Config directory exists: ${configDir}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.log(` [--] Config directory not found: ${configDir}`);
|
|
85
|
+
console.log(' Run: lazy-gravity setup (optional if using .env)');
|
|
86
|
+
}
|
|
87
|
+
// 2. Config file check
|
|
88
|
+
const configFilePath = configLoader_1.ConfigLoader.getConfigFilePath();
|
|
89
|
+
if (configLoader_1.ConfigLoader.configExists()) {
|
|
90
|
+
console.log(` [OK] Config file found: ${configFilePath}`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(` [--] Config file not found: ${configFilePath} (optional — .env fallback used)`);
|
|
94
|
+
}
|
|
95
|
+
// 3. .env file check
|
|
96
|
+
const env = checkEnvFile();
|
|
97
|
+
if (env.exists) {
|
|
98
|
+
// Load .env so subsequent checks can see the variables
|
|
99
|
+
require('dotenv').config({ path: env.path });
|
|
100
|
+
console.log(` [OK] .env file found: ${env.path}`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
if (!configLoader_1.ConfigLoader.configExists()) {
|
|
104
|
+
console.log(` [!!] .env file not found: ${env.path}`);
|
|
105
|
+
allOk = false;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.log(` [--] .env file not found: ${env.path} (not needed — config.json used)`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// 4. Required environment variables (check both env and config.json sources)
|
|
112
|
+
const vars = checkRequiredEnvVars();
|
|
113
|
+
for (const v of vars) {
|
|
114
|
+
if (v.set) {
|
|
115
|
+
console.log(` [OK] ${v.name} is set`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.log(` [!!] ${v.name} is NOT set`);
|
|
119
|
+
allOk = false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 5. CDP port check
|
|
123
|
+
console.log('\n Checking CDP ports...');
|
|
124
|
+
let cdpOk = false;
|
|
125
|
+
for (const port of cdpPorts_1.CDP_PORTS) {
|
|
126
|
+
const alive = await checkPort(port);
|
|
127
|
+
if (alive) {
|
|
128
|
+
console.log(` [OK] CDP port ${port} is responding`);
|
|
129
|
+
cdpOk = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!cdpOk) {
|
|
133
|
+
console.log(' [!!] No CDP ports responding');
|
|
134
|
+
console.log(' Run: open -a Antigravity --args --remote-debugging-port=9222');
|
|
135
|
+
allOk = false;
|
|
136
|
+
}
|
|
137
|
+
// 6. Node.js version check
|
|
138
|
+
const nodeVersion = process.versions.node;
|
|
139
|
+
const major = parseInt(nodeVersion.split('.')[0], 10);
|
|
140
|
+
if (major >= 18) {
|
|
141
|
+
console.log(`\n [OK] Node.js ${nodeVersion}`);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
console.log(`\n [!!] Node.js ${nodeVersion} (>= 18.0.0 required)`);
|
|
145
|
+
allOk = false;
|
|
146
|
+
}
|
|
147
|
+
// Summary
|
|
148
|
+
console.log('');
|
|
149
|
+
if (allOk) {
|
|
150
|
+
console.log(' All checks passed!');
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(' Some checks failed. Please fix the issues above.');
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.openAction = openAction;
|
|
37
|
+
const net = __importStar(require("net"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const cdpPorts_1 = require("../../utils/cdpPorts");
|
|
41
|
+
const APP_NAME = 'Antigravity';
|
|
42
|
+
const C = {
|
|
43
|
+
reset: '\x1b[0m',
|
|
44
|
+
bold: '\x1b[1m',
|
|
45
|
+
dim: '\x1b[2m',
|
|
46
|
+
cyan: '\x1b[36m',
|
|
47
|
+
green: '\x1b[32m',
|
|
48
|
+
red: '\x1b[31m',
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Check whether a TCP port is available (not in use) by attempting to listen on it.
|
|
52
|
+
*/
|
|
53
|
+
function isPortAvailable(port) {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const server = net.createServer();
|
|
56
|
+
server.once('error', () => resolve(false));
|
|
57
|
+
server.once('listening', () => {
|
|
58
|
+
server.close(() => resolve(true));
|
|
59
|
+
});
|
|
60
|
+
server.listen(port, '127.0.0.1');
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async function findAvailablePort() {
|
|
64
|
+
for (const port of cdpPorts_1.CDP_PORTS) {
|
|
65
|
+
if (await isPortAvailable(port)) {
|
|
66
|
+
return port;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function openMacOS(port) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
(0, child_process_1.execFile)('open', ['-a', APP_NAME, '--args', `--remote-debugging-port=${port}`], (err) => {
|
|
74
|
+
if (err) {
|
|
75
|
+
reject(new Error(`Failed to open ${APP_NAME}: ${err.message}`));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
resolve();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function openWindows(port) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
(0, child_process_1.execFile)(`${APP_NAME}.exe`, [`--remote-debugging-port=${port}`], { shell: true }, (err) => {
|
|
85
|
+
if (err) {
|
|
86
|
+
reject(new Error(`Failed to open ${APP_NAME}: ${err.message}`));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
resolve();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function openLinux(port) {
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
try {
|
|
96
|
+
const child = (0, child_process_1.spawn)(APP_NAME.toLowerCase(), [`--remote-debugging-port=${port}`], {
|
|
97
|
+
detached: true,
|
|
98
|
+
stdio: 'ignore',
|
|
99
|
+
});
|
|
100
|
+
child.unref();
|
|
101
|
+
child.on('error', (err) => {
|
|
102
|
+
reject(new Error(`Failed to open ${APP_NAME}: ${err.message}`));
|
|
103
|
+
});
|
|
104
|
+
// Give it a moment to detect spawn errors
|
|
105
|
+
setTimeout(() => resolve(), 500);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
109
|
+
reject(new Error(`Failed to open ${APP_NAME}: ${msg}`));
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async function openAction() {
|
|
114
|
+
const platform = os.platform();
|
|
115
|
+
console.log(`\n ${C.cyan}Searching for an available CDP port...${C.reset}`);
|
|
116
|
+
const port = await findAvailablePort();
|
|
117
|
+
if (port === null) {
|
|
118
|
+
console.log(` ${C.red}No available CDP ports found.${C.reset}`);
|
|
119
|
+
console.log(` ${C.dim}All candidate ports are in use: ${cdpPorts_1.CDP_PORTS.join(', ')}${C.reset}`);
|
|
120
|
+
console.log(` ${C.dim}Close an application using one of these ports and try again.${C.reset}\n`);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
console.log(` ${C.green}Found available port: ${port}${C.reset}`);
|
|
125
|
+
console.log(` ${C.dim}Opening ${APP_NAME} with --remote-debugging-port=${port}...${C.reset}\n`);
|
|
126
|
+
try {
|
|
127
|
+
if (platform === 'darwin') {
|
|
128
|
+
await openMacOS(port);
|
|
129
|
+
}
|
|
130
|
+
else if (platform === 'win32') {
|
|
131
|
+
await openWindows(port);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
await openLinux(port);
|
|
135
|
+
}
|
|
136
|
+
console.log(` ${C.green}${APP_NAME} opened on CDP port ${port}${C.reset}`);
|
|
137
|
+
console.log(` ${C.dim}Run ${C.reset}${C.cyan}lazy-gravity start${C.reset}${C.dim} to connect the bot.${C.reset}\n`);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
141
|
+
console.log(` ${C.red}${msg}${C.reset}`);
|
|
142
|
+
console.log(` ${C.dim}Make sure ${APP_NAME} is installed on your system.${C.reset}\n`);
|
|
143
|
+
process.exitCode = 1;
|
|
144
|
+
}
|
|
145
|
+
}
|