lazy-gravity 0.0.4 β 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -7
- package/dist/bin/cli.js +18 -18
- package/dist/bin/commands/doctor.js +25 -19
- package/dist/bin/commands/start.js +25 -2
- package/dist/bot/index.js +445 -126
- package/dist/commands/joinCommandHandler.js +302 -0
- package/dist/commands/joinDetachCommandHandler.js +285 -0
- package/dist/commands/registerSlashCommands.js +40 -0
- package/dist/commands/workspaceCommandHandler.js +17 -28
- package/dist/database/chatSessionRepository.js +10 -0
- package/dist/database/userPreferenceRepository.js +72 -0
- package/dist/events/interactionCreateHandler.js +338 -30
- package/dist/events/messageCreateHandler.js +161 -47
- package/dist/services/antigravityLauncher.js +4 -3
- package/dist/services/approvalDetector.js +7 -0
- package/dist/services/assistantDomExtractor.js +339 -0
- package/dist/services/cdpBridgeManager.js +323 -39
- package/dist/services/cdpConnectionPool.js +117 -33
- package/dist/services/cdpService.js +149 -53
- package/dist/services/chatSessionService.js +229 -8
- package/dist/services/errorPopupDetector.js +271 -0
- package/dist/services/planningDetector.js +318 -0
- package/dist/services/responseMonitor.js +308 -70
- package/dist/services/retryStore.js +46 -0
- package/dist/services/updateCheckService.js +147 -0
- package/dist/services/userMessageDetector.js +221 -0
- package/dist/ui/buttonUtils.js +33 -0
- package/dist/ui/modeUi.js +11 -1
- package/dist/ui/modelsUi.js +24 -13
- package/dist/ui/outputUi.js +30 -0
- package/dist/ui/projectListUi.js +83 -0
- package/dist/ui/sessionPickerUi.js +48 -0
- package/dist/utils/antigravityPaths.js +94 -0
- package/dist/utils/configLoader.js +18 -0
- package/dist/utils/discordButtonUtils.js +33 -0
- package/dist/utils/discordFormatter.js +149 -16
- package/dist/utils/htmlToDiscordMarkdown.js +184 -0
- package/dist/utils/logBuffer.js +47 -0
- package/dist/utils/logFileTransport.js +147 -0
- package/dist/utils/logger.js +86 -21
- package/dist/utils/pathUtils.js +57 -0
- package/dist/utils/plainTextFormatter.js +70 -0
- package/dist/utils/processLogBuffer.js +4 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<img src="https://img.shields.io/badge/version-0.0
|
|
6
|
+
<img src="https://img.shields.io/badge/version-0.2.0-blue?style=flat-square" alt="Version" />
|
|
7
|
+
<img src="https://img.shields.io/badge/Antigravity-1.19.5-ff6b35?style=flat-square" alt="Antigravity" />
|
|
7
8
|
<img src="https://img.shields.io/badge/node-18.x+-brightgreen?style=flat-square&logo=node.js" alt="Node.js" />
|
|
8
9
|
<img src="https://img.shields.io/badge/discord.js-14.x-5865F2?style=flat-square&logo=discord&logoColor=white" alt="discord.js" />
|
|
9
10
|
<img src="https://img.shields.io/badge/protocol-CDP%20%2F%20WebSocket-orange?style=flat-square" alt="CDP/WebSocket" />
|
|
@@ -16,11 +17,7 @@
|
|
|
16
17
|
|
|
17
18
|
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
|
|
|
19
|
-
|
|
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>
|
|
20
|
+
https://github.com/user-attachments/assets/08eac63e-5ede-469b-ac6c-1c40ec77b0c0
|
|
24
21
|
|
|
25
22
|
|
|
26
23
|
## Quick Setup
|
|
@@ -85,10 +82,15 @@ Just type in any bound channel:
|
|
|
85
82
|
- `π /template list` β Display registered templates with execute buttons
|
|
86
83
|
- `π /template add <name> <prompt>` β Register a new prompt template
|
|
87
84
|
- `π /template delete <name>` β Delete a template
|
|
85
|
+
- `π /join` β Join an existing Antigravity session (shows up to 20 recent sessions)
|
|
86
|
+
- `π /mirror` β Toggle PCβDiscord message mirroring for the current session
|
|
88
87
|
- `π /stop` β Force-stop a running Antigravity task
|
|
89
88
|
- `πΈ /screenshot` β Capture and send Antigravity's current screen
|
|
90
89
|
- `π§ /status` β Show bot connection status, current mode, and active project
|
|
91
90
|
- `β
/autoaccept [on|off|status]` β Toggle auto-approval of file edit dialogs
|
|
91
|
+
- `π /output [embed|plain]` β Toggle output format between Embed and Plain Text (plain text is easier to copy on mobile)
|
|
92
|
+
- `π /logs [lines] [level]` β View recent bot logs (ephemeral)
|
|
93
|
+
- `π /ping` β Check bot latency
|
|
92
94
|
- `π§Ή /cleanup [days]` β Scan and clean up inactive session channels (default: 7 days)
|
|
93
95
|
- `β /help` β Display list of available commands
|
|
94
96
|
|
|
@@ -100,6 +102,8 @@ lazy-gravity setup # Interactive setup wizard
|
|
|
100
102
|
lazy-gravity open # Open Antigravity with CDP (auto-selects available port)
|
|
101
103
|
lazy-gravity start # Start the Discord bot
|
|
102
104
|
lazy-gravity doctor # Check environment and dependencies
|
|
105
|
+
lazy-gravity --verbose # Show debug-level logs (CDP details, detector events, etc.)
|
|
106
|
+
lazy-gravity --quiet # Only show errors
|
|
103
107
|
lazy-gravity --version # Show version
|
|
104
108
|
lazy-gravity --help # Show help
|
|
105
109
|
```
|
|
@@ -117,7 +121,10 @@ lazy-gravity setup
|
|
|
117
121
|
|
|
118
122
|
The wizard guides you through 4 steps:
|
|
119
123
|
|
|
120
|
-
1. **Discord Bot Token** β create a bot at the [Discord Developer Portal](https://discord.com/developers/applications)
|
|
124
|
+
1. **Discord Bot Token** β create a bot at the [Discord Developer Portal](https://discord.com/developers/applications).
|
|
125
|
+
- Enable Privileged Gateway Intents: **PRESENCE, SERVER MEMBERS, MESSAGE CONTENT**.
|
|
126
|
+
- Generate an OAuth2 invite URL with the following bot permissions: **Manage Channels** (required for `/project`), **Send Messages**, **Embed Links**, **Attach Files**, **Read Message History**, and **Add Reactions**.
|
|
127
|
+
- Invite the bot to your server, then copy the bot token. Client ID is extracted from the token automatically.
|
|
121
128
|
2. **Guild (Server) ID** β for instant slash command registration (optional; press Enter to skip).
|
|
122
129
|
3. **Allowed User IDs** β Discord users authorized to interact with the bot.
|
|
123
130
|
4. **Workspace Directory** β parent directory where your coding projects live.
|
|
@@ -145,6 +152,7 @@ DISCORD_BOT_TOKEN=your_bot_token_here
|
|
|
145
152
|
GUILD_ID=your_guild_id_here
|
|
146
153
|
ALLOWED_USER_IDS=123456789,987654321
|
|
147
154
|
WORKSPACE_BASE_DIR=~/Code
|
|
155
|
+
# ANTIGRAVITY_PATH=/path/to/antigravity.AppImage # Optional: For Linux users or custom installations
|
|
148
156
|
```
|
|
149
157
|
|
|
150
158
|
Then start the bot:
|
|
@@ -182,6 +190,13 @@ Double-click **`start_antigravity_win.bat`** in the repo root.
|
|
|
182
190
|
|
|
183
191
|
- **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
192
|
|
|
193
|
+
#### Linux
|
|
194
|
+
On Linux (especially when using AppImages), the `antigravity` command might not be globally available.
|
|
195
|
+
You can specify the exact path to your executable by setting the `ANTIGRAVITY_PATH` environment variable in your `.env` file:
|
|
196
|
+
```env
|
|
197
|
+
ANTIGRAVITY_PATH=/opt/applications/antigravity.AppImage
|
|
198
|
+
```
|
|
199
|
+
|
|
185
200
|
> **Tip**: CDP ports are auto-scanned from candidates (9222, 9223, 9333, 9444, 9555, 9666).
|
|
186
201
|
> Launch Antigravity first, then start the bot β it connects automatically.
|
|
187
202
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -43,37 +43,37 @@ const doctor_1 = require("./commands/doctor");
|
|
|
43
43
|
const setup_1 = require("./commands/setup");
|
|
44
44
|
const open_1 = require("./commands/open");
|
|
45
45
|
const configLoader_1 = require("../utils/configLoader");
|
|
46
|
-
let commandRan = false;
|
|
47
|
-
const markRan = (fn) => ((...args) => { commandRan = true; return fn(...args); });
|
|
48
46
|
const program = new commander_1.Command()
|
|
49
47
|
.name('lazy-gravity')
|
|
50
48
|
.description('Control your AI coding assistant from Discord')
|
|
51
|
-
.version(package_json_1.version)
|
|
49
|
+
.version(package_json_1.version)
|
|
50
|
+
.option('--verbose', 'Show debug-level logs')
|
|
51
|
+
.option('--quiet', 'Only show errors');
|
|
52
|
+
// Default action: no subcommand β start or setup
|
|
53
|
+
program.action(() => {
|
|
54
|
+
const hasConfig = configLoader_1.ConfigLoader.configExists();
|
|
55
|
+
const hasEnv = fs.existsSync(path.resolve(process.cwd(), '.env'));
|
|
56
|
+
if (!hasConfig && !hasEnv) {
|
|
57
|
+
(0, setup_1.setupAction)();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
(0, start_1.startAction)(program.opts(), program);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
52
63
|
program
|
|
53
64
|
.command('start')
|
|
54
65
|
.description('Start the Discord bot')
|
|
55
|
-
.action(
|
|
66
|
+
.action((_opts, cmd) => (0, start_1.startAction)(cmd.parent.opts(), cmd.parent));
|
|
56
67
|
program
|
|
57
68
|
.command('doctor')
|
|
58
69
|
.description('Check environment and dependencies')
|
|
59
|
-
.action(
|
|
70
|
+
.action(doctor_1.doctorAction);
|
|
60
71
|
program
|
|
61
72
|
.command('setup')
|
|
62
73
|
.description('Interactive setup wizard')
|
|
63
|
-
.action(
|
|
74
|
+
.action(setup_1.setupAction);
|
|
64
75
|
program
|
|
65
76
|
.command('open')
|
|
66
77
|
.description('Open Antigravity with CDP enabled (auto-selects available port)')
|
|
67
|
-
.action(
|
|
78
|
+
.action(open_1.openAction);
|
|
68
79
|
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
|
-
}
|
|
@@ -39,6 +39,12 @@ const fs = __importStar(require("fs"));
|
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const cdpPorts_1 = require("../../utils/cdpPorts");
|
|
41
41
|
const configLoader_1 = require("../../utils/configLoader");
|
|
42
|
+
const pathUtils_1 = require("../../utils/pathUtils");
|
|
43
|
+
const logger_1 = require("../../utils/logger");
|
|
44
|
+
const ok = (msg) => console.log(` ${logger_1.COLORS.green}[OK]${logger_1.COLORS.reset} ${msg}`);
|
|
45
|
+
const warn = (msg) => console.log(` ${logger_1.COLORS.yellow}[--]${logger_1.COLORS.reset} ${msg}`);
|
|
46
|
+
const fail = (msg) => console.log(` ${logger_1.COLORS.red}[!!]${logger_1.COLORS.reset} ${msg}`);
|
|
47
|
+
const hint = (msg) => console.log(` ${logger_1.COLORS.dim}${msg}${logger_1.COLORS.reset}`);
|
|
42
48
|
function checkPort(port) {
|
|
43
49
|
return new Promise((resolve) => {
|
|
44
50
|
const req = http.get(`http://127.0.0.1:${port}/json/list`, (res) => {
|
|
@@ -73,84 +79,84 @@ function checkRequiredEnvVars() {
|
|
|
73
79
|
}));
|
|
74
80
|
}
|
|
75
81
|
async function doctorAction() {
|
|
76
|
-
console.log(
|
|
82
|
+
console.log(`\n${logger_1.COLORS.cyan}lazy-gravity doctor${logger_1.COLORS.reset}\n`);
|
|
77
83
|
let allOk = true;
|
|
78
84
|
// 1. Config directory check
|
|
79
85
|
const configDir = configLoader_1.ConfigLoader.getConfigDir();
|
|
80
86
|
if (fs.existsSync(configDir)) {
|
|
81
|
-
|
|
87
|
+
ok(`Config directory exists: ${configDir}`);
|
|
82
88
|
}
|
|
83
89
|
else {
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
warn(`Config directory not found: ${configDir}`);
|
|
91
|
+
hint('Run: lazy-gravity setup (optional if using .env)');
|
|
86
92
|
}
|
|
87
93
|
// 2. Config file check
|
|
88
94
|
const configFilePath = configLoader_1.ConfigLoader.getConfigFilePath();
|
|
89
95
|
if (configLoader_1.ConfigLoader.configExists()) {
|
|
90
|
-
|
|
96
|
+
ok(`Config file found: ${configFilePath}`);
|
|
91
97
|
}
|
|
92
98
|
else {
|
|
93
|
-
|
|
99
|
+
warn(`Config file not found: ${configFilePath} (optional β .env fallback used)`);
|
|
94
100
|
}
|
|
95
101
|
// 3. .env file check
|
|
96
102
|
const env = checkEnvFile();
|
|
97
103
|
if (env.exists) {
|
|
98
104
|
// Load .env so subsequent checks can see the variables
|
|
99
105
|
require('dotenv').config({ path: env.path });
|
|
100
|
-
|
|
106
|
+
ok(`.env file found: ${env.path}`);
|
|
101
107
|
}
|
|
102
108
|
else {
|
|
103
109
|
if (!configLoader_1.ConfigLoader.configExists()) {
|
|
104
|
-
|
|
110
|
+
fail(`.env file not found: ${env.path}`);
|
|
105
111
|
allOk = false;
|
|
106
112
|
}
|
|
107
113
|
else {
|
|
108
|
-
|
|
114
|
+
warn(`.env file not found: ${env.path} (not needed β config.json used)`);
|
|
109
115
|
}
|
|
110
116
|
}
|
|
111
117
|
// 4. Required environment variables (check both env and config.json sources)
|
|
112
118
|
const vars = checkRequiredEnvVars();
|
|
113
119
|
for (const v of vars) {
|
|
114
120
|
if (v.set) {
|
|
115
|
-
|
|
121
|
+
ok(`${v.name} is set`);
|
|
116
122
|
}
|
|
117
123
|
else {
|
|
118
|
-
|
|
124
|
+
fail(`${v.name} is NOT set`);
|
|
119
125
|
allOk = false;
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
// 5. CDP port check
|
|
123
|
-
console.log(
|
|
129
|
+
console.log(`\n ${logger_1.COLORS.dim}Checking CDP ports...${logger_1.COLORS.reset}`);
|
|
124
130
|
let cdpOk = false;
|
|
125
131
|
for (const port of cdpPorts_1.CDP_PORTS) {
|
|
126
132
|
const alive = await checkPort(port);
|
|
127
133
|
if (alive) {
|
|
128
|
-
|
|
134
|
+
ok(`CDP port ${port} is responding`);
|
|
129
135
|
cdpOk = true;
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
if (!cdpOk) {
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
fail('No CDP ports responding');
|
|
140
|
+
hint(`Run: ${(0, pathUtils_1.getAntigravityCdpHint)(9222)}`);
|
|
135
141
|
allOk = false;
|
|
136
142
|
}
|
|
137
143
|
// 6. Node.js version check
|
|
138
144
|
const nodeVersion = process.versions.node;
|
|
139
145
|
const major = parseInt(nodeVersion.split('.')[0], 10);
|
|
140
146
|
if (major >= 18) {
|
|
141
|
-
|
|
147
|
+
ok(`Node.js ${nodeVersion}`);
|
|
142
148
|
}
|
|
143
149
|
else {
|
|
144
|
-
|
|
150
|
+
fail(`Node.js ${nodeVersion} (>= 18.0.0 required)`);
|
|
145
151
|
allOk = false;
|
|
146
152
|
}
|
|
147
153
|
// Summary
|
|
148
154
|
console.log('');
|
|
149
155
|
if (allOk) {
|
|
150
|
-
console.log(
|
|
156
|
+
console.log(` ${logger_1.COLORS.green}All checks passed!${logger_1.COLORS.reset}`);
|
|
151
157
|
}
|
|
152
158
|
else {
|
|
153
|
-
console.log(
|
|
159
|
+
console.log(` ${logger_1.COLORS.red}Some checks failed. Please fix the issues above.${logger_1.COLORS.reset}`);
|
|
154
160
|
process.exitCode = 1;
|
|
155
161
|
}
|
|
156
162
|
}
|
|
@@ -5,10 +5,33 @@ const logo_1 = require("../../utils/logo");
|
|
|
5
5
|
const lockfile_1 = require("../../utils/lockfile");
|
|
6
6
|
const bot_1 = require("../../bot");
|
|
7
7
|
const logger_1 = require("../../utils/logger");
|
|
8
|
-
|
|
8
|
+
const package_json_1 = require("../../../package.json");
|
|
9
|
+
const updateCheckService_1 = require("../../services/updateCheckService");
|
|
10
|
+
/**
|
|
11
|
+
* Resolve log level from CLI flags on the root program.
|
|
12
|
+
* Priority: --verbose > --quiet > undefined (fall through to env/config)
|
|
13
|
+
*/
|
|
14
|
+
function resolveCliLogLevel(cmd) {
|
|
15
|
+
if (!cmd)
|
|
16
|
+
return undefined;
|
|
17
|
+
const root = cmd.parent ?? cmd;
|
|
18
|
+
const opts = root.opts();
|
|
19
|
+
if (opts.verbose)
|
|
20
|
+
return 'debug';
|
|
21
|
+
if (opts.quiet)
|
|
22
|
+
return 'error';
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
async function startAction(_opts, cmd) {
|
|
26
|
+
const cliLevel = resolveCliLogLevel(cmd);
|
|
27
|
+
if (cliLevel) {
|
|
28
|
+
logger_1.logger.setLogLevel(cliLevel);
|
|
29
|
+
}
|
|
9
30
|
console.log(logo_1.LOGO);
|
|
10
31
|
(0, lockfile_1.acquireLock)();
|
|
11
|
-
|
|
32
|
+
// Non-blocking update check (fire-and-forget)
|
|
33
|
+
(0, updateCheckService_1.checkForUpdates)(package_json_1.version).catch(() => { });
|
|
34
|
+
await (0, bot_1.startBot)(cliLevel).catch((err) => {
|
|
12
35
|
logger_1.logger.error('Failed to start bot:', err);
|
|
13
36
|
process.exit(1);
|
|
14
37
|
});
|