lazy-gravity 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +93 -20
  2. package/dist/bin/cli.js +18 -18
  3. package/dist/bin/commands/doctor.js +21 -3
  4. package/dist/bin/commands/setup.js +286 -70
  5. package/dist/bin/commands/start.js +25 -2
  6. package/dist/bot/eventRouter.js +70 -0
  7. package/dist/bot/index.js +685 -285
  8. package/dist/bot/telegramCommands.js +428 -0
  9. package/dist/bot/telegramMessageHandler.js +304 -0
  10. package/dist/bot/telegramProjectCommand.js +137 -0
  11. package/dist/bot/workspaceQueue.js +61 -0
  12. package/dist/commands/joinCommandHandler.js +305 -0
  13. package/dist/commands/joinDetachCommandHandler.js +285 -0
  14. package/dist/commands/registerSlashCommands.js +35 -0
  15. package/dist/database/chatSessionRepository.js +10 -0
  16. package/dist/database/telegramBindingRepository.js +97 -0
  17. package/dist/database/userPreferenceRepository.js +117 -0
  18. package/dist/events/interactionCreateHandler.js +94 -36
  19. package/dist/events/messageCreateHandler.js +162 -53
  20. package/dist/handlers/approvalButtonAction.js +99 -0
  21. package/dist/handlers/autoAcceptButtonAction.js +43 -0
  22. package/dist/handlers/buttonHandler.js +55 -0
  23. package/dist/handlers/commandHandler.js +44 -0
  24. package/dist/handlers/errorPopupButtonAction.js +137 -0
  25. package/dist/handlers/messageHandler.js +70 -0
  26. package/dist/handlers/modeSelectAction.js +63 -0
  27. package/dist/handlers/modelButtonAction.js +102 -0
  28. package/dist/handlers/planningButtonAction.js +118 -0
  29. package/dist/handlers/selectHandler.js +41 -0
  30. package/dist/handlers/templateButtonAction.js +54 -0
  31. package/dist/platform/adapter.js +8 -0
  32. package/dist/platform/discord/discordAdapter.js +99 -0
  33. package/dist/platform/discord/index.js +15 -0
  34. package/dist/platform/discord/wrappers.js +331 -0
  35. package/dist/platform/index.js +18 -0
  36. package/dist/platform/richContentBuilder.js +76 -0
  37. package/dist/platform/telegram/index.js +16 -0
  38. package/dist/platform/telegram/telegramAdapter.js +195 -0
  39. package/dist/platform/telegram/telegramFormatter.js +134 -0
  40. package/dist/platform/telegram/wrappers.js +329 -0
  41. package/dist/platform/types.js +28 -0
  42. package/dist/services/antigravityLauncher.js +4 -3
  43. package/dist/services/approvalDetector.js +21 -2
  44. package/dist/services/cdpBridgeManager.js +189 -144
  45. package/dist/services/cdpConnectionPool.js +79 -51
  46. package/dist/services/cdpService.js +149 -51
  47. package/dist/services/chatSessionService.js +229 -8
  48. package/dist/services/defaultModelApplicator.js +54 -0
  49. package/dist/services/errorPopupDetector.js +6 -0
  50. package/dist/services/modeService.js +16 -1
  51. package/dist/services/modelService.js +57 -16
  52. package/dist/services/notificationSender.js +149 -0
  53. package/dist/services/planningDetector.js +6 -0
  54. package/dist/services/responseMonitor.js +126 -26
  55. package/dist/services/updateCheckService.js +147 -0
  56. package/dist/services/userMessageDetector.js +221 -0
  57. package/dist/ui/autoAcceptUi.js +37 -0
  58. package/dist/ui/modeUi.js +48 -1
  59. package/dist/ui/modelsUi.js +96 -0
  60. package/dist/ui/outputUi.js +62 -0
  61. package/dist/ui/projectListUi.js +55 -0
  62. package/dist/ui/screenshotUi.js +26 -0
  63. package/dist/ui/sessionPickerUi.js +82 -0
  64. package/dist/ui/templateUi.js +41 -0
  65. package/dist/utils/antigravityPaths.js +94 -0
  66. package/dist/utils/configLoader.js +73 -12
  67. package/dist/utils/discordButtonUtils.js +33 -0
  68. package/dist/utils/lockfile.js +5 -5
  69. package/dist/utils/logBuffer.js +47 -0
  70. package/dist/utils/logger.js +87 -20
  71. package/dist/utils/pathUtils.js +57 -0
  72. package/dist/utils/plainTextFormatter.js +70 -0
  73. package/dist/utils/telegramImageHandler.js +127 -0
  74. package/package.json +7 -5
package/README.md CHANGED
@@ -3,24 +3,22 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <img src="https://img.shields.io/badge/version-0.0.4-blue?style=flat-square" alt="Version" />
6
+ <img src="https://img.shields.io/badge/version-0.3.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" />
10
+ <img src="https://img.shields.io/badge/telegram-optional-26A5E4?style=flat-square&logo=telegram&logoColor=white" alt="Telegram" />
9
11
  <img src="https://img.shields.io/badge/protocol-CDP%20%2F%20WebSocket-orange?style=flat-square" alt="CDP/WebSocket" />
10
12
  <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License" />
11
13
  </p>
12
14
 
13
15
  # LazyGravity
14
16
 
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.
17
+ **LazyGravity** is a local, secure bot that lets you remotely operate [Antigravity](https://antigravity.dev) on your home PC — from your smartphone, anywhere. Supports **Discord** and **Telegram** (optional).
16
18
 
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.
19
+ 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 your chat platform.
18
20
 
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>
21
+ https://github.com/user-attachments/assets/08eac63e-5ede-469b-ac6c-1c40ec77b0c0
24
22
 
25
23
 
26
24
  ## Quick Setup
@@ -36,7 +34,7 @@ The interactive wizard walks you through Discord bot creation, token setup, and
36
34
 
37
35
  ```bash
38
36
  lazy-gravity open # Launch Antigravity with CDP enabled
39
- lazy-gravity start # Start the Discord bot
37
+ lazy-gravity start # Start the bot (Discord by default, or both platforms)
40
38
  ```
41
39
 
42
40
  Or run directly without installing:
@@ -50,23 +48,30 @@ npx lazy-gravity
50
48
  ## Features
51
49
 
52
50
  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.
51
+ - **No external server or port exposure** — runs as a local process on your PC, communicating directly with Discord/Telegram.
52
+ - **Whitelist access control**: only authorized user IDs can interact with the bot (per-platform allowlists).
55
53
  - **Secure credential management**: Bot tokens and API keys are stored locally (never in source code).
56
54
  - **Path traversal prevention & resource protection**: sandboxed directory access and concurrent task limits prevent abuse.
57
55
 
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.
56
+ 2. **Multi-Platform Support**
57
+ - **Discord** (default): Full feature set with slash commands, rich embeds, reactions, and channel management.
58
+ - **Telegram** (optional): Send prompts, receive responses, and use inline keyboard buttons. Requires [grammy](https://grammy.dev/) (`npm install grammy`).
59
+ - Run both platforms simultaneously from a single process, or use either one standalone.
60
+
61
+ 3. **Project Management (Channel-Directory Binding)**
62
+ - **Discord**: Use `/project` to bind a channel to a local project directory via an interactive select menu.
63
+ - **Telegram**: Use `/project` to bind a chat to a workspace directory.
64
+ - Messages sent in a bound channel/chat are automatically forwarded to Antigravity with the correct project context.
61
65
 
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.
66
+ 4. **Context-Aware Replies**
67
+ - **Discord**: Results delivered as rich Embeds. Use Reply to continue the conversation with full context preserved.
68
+ - **Telegram**: Results delivered as formatted HTML messages with inline keyboard buttons.
64
69
 
65
- 4. **Real-Time Progress Monitoring**
70
+ 5. **Real-Time Progress Monitoring**
66
71
  - Long-running Antigravity tasks report progress as a series of messages (delivery confirmed / planning / analysis / execution / implementation / final summary).
67
72
 
68
- 5. **File Attachments & Context Parsing**
69
- - Send images (screenshots, mockups) or text files via Discord — they are automatically forwarded to Antigravity as context.
73
+ 6. **File Attachments & Context Parsing**
74
+ - Send images (screenshots, mockups) or text files — they are automatically forwarded to Antigravity as context.
70
75
 
71
76
  ## Usage & Commands
72
77
 
@@ -85,13 +90,37 @@ Just type in any bound channel:
85
90
  - `📝 /template list` — Display registered templates with execute buttons
86
91
  - `📝 /template add <name> <prompt>` — Register a new prompt template
87
92
  - `📝 /template delete <name>` — Delete a template
93
+ - `🔗 /join` — Join an existing Antigravity session (shows up to 20 recent sessions)
94
+ - `🔗 /mirror` — Toggle PC→Discord message mirroring for the current session
88
95
  - `🛑 /stop` — Force-stop a running Antigravity task
89
96
  - `📸 /screenshot` — Capture and send Antigravity's current screen
90
97
  - `🔧 /status` — Show bot connection status, current mode, and active project
91
98
  - `✅ /autoaccept [on|off|status]` — Toggle auto-approval of file edit dialogs
99
+ - `📝 /output [embed|plain]` — Toggle output format between Embed and Plain Text (plain text is easier to copy on mobile)
100
+ - `📋 /logs [lines] [level]` — View recent bot logs (ephemeral)
101
+ - `🏓 /ping` — Check bot latency
92
102
  - `🧹 /cleanup [days]` — Scan and clean up inactive session channels (default: 7 days)
93
103
  - `❓ /help` — Display list of available commands
94
104
 
105
+ ### Telegram Commands
106
+
107
+ Telegram commands use underscores instead of subcommand syntax (Telegram does not allow hyphens or spaces in command names).
108
+
109
+ - `/project` — Manage workspace bindings (list, select, create)
110
+ - `/project_create <name>` — Create a new workspace directory
111
+ - `/template` — List prompt templates with execute buttons
112
+ - `/template_add <name> <prompt>` — Add a new prompt template
113
+ - `/template_delete <name>` — Delete a prompt template
114
+ - `/mode` — Switch execution mode
115
+ - `/model` — Switch LLM model
116
+ - `/screenshot` — Capture Antigravity screenshot
117
+ - `/autoaccept [on|off]` — Toggle auto-accept mode
118
+ - `/logs [count]` — Show recent log entries
119
+ - `/stop` — Interrupt active LLM generation
120
+ - `/status` — Show bot status and connections
121
+ - `/ping` — Check bot latency
122
+ - `/help` — Show available commands
123
+
95
124
  ### CLI Commands
96
125
 
97
126
  ```bash
@@ -100,6 +129,8 @@ lazy-gravity setup # Interactive setup wizard
100
129
  lazy-gravity open # Open Antigravity with CDP (auto-selects available port)
101
130
  lazy-gravity start # Start the Discord bot
102
131
  lazy-gravity doctor # Check environment and dependencies
132
+ lazy-gravity --verbose # Show debug-level logs (CDP details, detector events, etc.)
133
+ lazy-gravity --quiet # Only show errors
103
134
  lazy-gravity --version # Show version
104
135
  lazy-gravity --help # Show help
105
136
  ```
@@ -148,6 +179,7 @@ DISCORD_BOT_TOKEN=your_bot_token_here
148
179
  GUILD_ID=your_guild_id_here
149
180
  ALLOWED_USER_IDS=123456789,987654321
150
181
  WORKSPACE_BASE_DIR=~/Code
182
+ # ANTIGRAVITY_PATH=/path/to/antigravity.AppImage # Optional: For Linux users or custom installations
151
183
  ```
152
184
 
153
185
  Then start the bot:
@@ -156,6 +188,20 @@ Then start the bot:
156
188
  npm run start
157
189
  ```
158
190
 
191
+ #### Adding Telegram Support (Optional)
192
+
193
+ 1. Install grammy: `npm install grammy`
194
+ 2. Create a bot via [@BotFather](https://t.me/BotFather) on Telegram and copy the token.
195
+ 3. Add the following to your `.env`:
196
+
197
+ ```env
198
+ PLATFORMS=discord,telegram # or just "telegram" for Telegram-only
199
+ TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
200
+ TELEGRAM_ALLOWED_USER_IDS=123456789 # Your Telegram numeric user ID
201
+ ```
202
+
203
+ For Telegram-only deployments, Discord credentials (`DISCORD_BOT_TOKEN`, `CLIENT_ID`, `ALLOWED_USER_IDS`) are not required.
204
+
159
205
  Alternatively, you can build and use the CLI:
160
206
 
161
207
  ```bash
@@ -185,6 +231,13 @@ Double-click **`start_antigravity_win.bat`** in the repo root.
185
231
 
186
232
  - **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"`).
187
233
 
234
+ #### Linux
235
+ On Linux (especially when using AppImages), the `antigravity` command might not be globally available.
236
+ You can specify the exact path to your executable by setting the `ANTIGRAVITY_PATH` environment variable in your `.env` file:
237
+ ```env
238
+ ANTIGRAVITY_PATH=/opt/applications/antigravity.AppImage
239
+ ```
240
+
188
241
  > **Tip**: CDP ports are auto-scanned from candidates (9222, 9223, 9333, 9444, 9555, 9666).
189
242
  > Launch Antigravity first, then start the bot — it connects automatically.
190
243
 
@@ -220,7 +273,27 @@ Run `lazy-gravity doctor` to diagnose configuration and connectivity issues.
220
273
  2. Connects via WebSocket to CDP (`Runtime.evaluate` for DOM operations)
221
274
  3. Injects messages into the chat input, monitors Antigravity responses, and captures screenshots
222
275
 
223
- **On disconnect**: automatically retries up to 3 times (`maxReconnectAttempts`). If all retries fail, an error notification is sent to Discord.
276
+ **On disconnect**: automatically retries up to 3 times (`maxReconnectAttempts`). If all retries fail, an error notification is sent to the active chat platform.
277
+
278
+ ## Platform Architecture
279
+
280
+ LazyGravity uses a **platform abstraction layer** so the core bot logic is platform-independent:
281
+
282
+ ```
283
+ src/platform/
284
+ ├── types.ts # Shared interfaces (PlatformMessage, PlatformChannel, etc.)
285
+ ├── adapter.ts # PlatformAdapter interface
286
+ ├── richContentBuilder.ts # Immutable builder for rich content (embeds/HTML)
287
+ ├── discord/ # Discord adapter (discord.js wrappers)
288
+ │ ├── discordAdapter.ts
289
+ │ └── wrappers.ts
290
+ └── telegram/ # Telegram adapter (grammy-compatible wrappers)
291
+ ├── telegramAdapter.ts
292
+ ├── telegramFormatter.ts # Markdown → Telegram HTML conversion
293
+ └── wrappers.ts
294
+ ```
295
+
296
+ Both adapters implement the same `PlatformAdapter` interface and emit events through `PlatformAdapterEvents`. The `EventRouter` dispatches events to platform-agnostic handlers, and the `WorkspaceQueue` serializes concurrent requests per workspace across platforms.
224
297
 
225
298
  ## License
226
299
 
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(markRan(start_1.startAction));
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(markRan(doctor_1.doctorAction));
70
+ .action(doctor_1.doctorAction);
60
71
  program
61
72
  .command('setup')
62
73
  .description('Interactive setup wizard')
63
- .action(markRan(setup_1.setupAction));
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(markRan(open_1.openAction));
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,7 @@ 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");
42
43
  const logger_1 = require("../../utils/logger");
43
44
  const ok = (msg) => console.log(` ${logger_1.COLORS.green}[OK]${logger_1.COLORS.reset} ${msg}`);
44
45
  const warn = (msg) => console.log(` ${logger_1.COLORS.yellow}[--]${logger_1.COLORS.reset} ${msg}`);
@@ -70,8 +71,23 @@ function checkEnvFile() {
70
71
  const envPath = path.resolve(process.cwd(), '.env');
71
72
  return { exists: fs.existsSync(envPath), path: envPath };
72
73
  }
74
+ const VALID_PLATFORMS = ['discord', 'telegram'];
75
+ function getActivePlatforms() {
76
+ const raw = process.env.PLATFORMS || 'discord';
77
+ return raw
78
+ .split(',')
79
+ .map((p) => p.trim().toLowerCase())
80
+ .filter((p) => VALID_PLATFORMS.includes(p));
81
+ }
73
82
  function checkRequiredEnvVars() {
74
- const required = ['DISCORD_BOT_TOKEN', 'CLIENT_ID', 'ALLOWED_USER_IDS'];
83
+ const platforms = getActivePlatforms();
84
+ const required = [];
85
+ if (platforms.includes('discord')) {
86
+ required.push('DISCORD_BOT_TOKEN', 'CLIENT_ID', 'ALLOWED_USER_IDS');
87
+ }
88
+ if (platforms.includes('telegram')) {
89
+ required.push('TELEGRAM_BOT_TOKEN', 'TELEGRAM_ALLOWED_USER_IDS');
90
+ }
75
91
  return required.map((name) => ({
76
92
  name,
77
93
  set: Boolean(process.env[name]),
@@ -113,7 +129,9 @@ async function doctorAction() {
113
129
  warn(`.env file not found: ${env.path} (not needed — config.json used)`);
114
130
  }
115
131
  }
116
- // 4. Required environment variables (check both env and config.json sources)
132
+ // 4. Required environment variables (platform-aware)
133
+ const platforms = getActivePlatforms();
134
+ ok(`Active platforms: ${platforms.join(', ')}`);
117
135
  const vars = checkRequiredEnvVars();
118
136
  for (const v of vars) {
119
137
  if (v.set) {
@@ -136,7 +154,7 @@ async function doctorAction() {
136
154
  }
137
155
  if (!cdpOk) {
138
156
  fail('No CDP ports responding');
139
- hint('Run: open -a Antigravity --args --remote-debugging-port=9222');
157
+ hint(`Run: ${(0, pathUtils_1.getAntigravityCdpHint)(9222)}`);
140
158
  allOk = false;
141
159
  }
142
160
  // 6. Node.js version check