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.
Files changed (44) hide show
  1. package/README.md +22 -7
  2. package/dist/bin/cli.js +18 -18
  3. package/dist/bin/commands/doctor.js +25 -19
  4. package/dist/bin/commands/start.js +25 -2
  5. package/dist/bot/index.js +445 -126
  6. package/dist/commands/joinCommandHandler.js +302 -0
  7. package/dist/commands/joinDetachCommandHandler.js +285 -0
  8. package/dist/commands/registerSlashCommands.js +40 -0
  9. package/dist/commands/workspaceCommandHandler.js +17 -28
  10. package/dist/database/chatSessionRepository.js +10 -0
  11. package/dist/database/userPreferenceRepository.js +72 -0
  12. package/dist/events/interactionCreateHandler.js +338 -30
  13. package/dist/events/messageCreateHandler.js +161 -47
  14. package/dist/services/antigravityLauncher.js +4 -3
  15. package/dist/services/approvalDetector.js +7 -0
  16. package/dist/services/assistantDomExtractor.js +339 -0
  17. package/dist/services/cdpBridgeManager.js +323 -39
  18. package/dist/services/cdpConnectionPool.js +117 -33
  19. package/dist/services/cdpService.js +149 -53
  20. package/dist/services/chatSessionService.js +229 -8
  21. package/dist/services/errorPopupDetector.js +271 -0
  22. package/dist/services/planningDetector.js +318 -0
  23. package/dist/services/responseMonitor.js +308 -70
  24. package/dist/services/retryStore.js +46 -0
  25. package/dist/services/updateCheckService.js +147 -0
  26. package/dist/services/userMessageDetector.js +221 -0
  27. package/dist/ui/buttonUtils.js +33 -0
  28. package/dist/ui/modeUi.js +11 -1
  29. package/dist/ui/modelsUi.js +24 -13
  30. package/dist/ui/outputUi.js +30 -0
  31. package/dist/ui/projectListUi.js +83 -0
  32. package/dist/ui/sessionPickerUi.js +48 -0
  33. package/dist/utils/antigravityPaths.js +94 -0
  34. package/dist/utils/configLoader.js +18 -0
  35. package/dist/utils/discordButtonUtils.js +33 -0
  36. package/dist/utils/discordFormatter.js +149 -16
  37. package/dist/utils/htmlToDiscordMarkdown.js +184 -0
  38. package/dist/utils/logBuffer.js +47 -0
  39. package/dist/utils/logFileTransport.js +147 -0
  40. package/dist/utils/logger.js +86 -21
  41. package/dist/utils/pathUtils.js +57 -0
  42. package/dist/utils/plainTextFormatter.js +70 -0
  43. package/dist/utils/processLogBuffer.js +4 -0
  44. 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.1-blue?style=flat-square" alt="Version" />
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
- <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>
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), enable Privileged Gateway Intents (PRESENCE, SERVER MEMBERS, MESSAGE CONTENT), and copy the token. Client ID is extracted from the token automatically.
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(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,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('lazy-gravity doctor\n');
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
- console.log(` [OK] Config directory exists: ${configDir}`);
87
+ ok(`Config directory exists: ${configDir}`);
82
88
  }
83
89
  else {
84
- console.log(` [--] Config directory not found: ${configDir}`);
85
- console.log(' Run: lazy-gravity setup (optional if using .env)');
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
- console.log(` [OK] Config file found: ${configFilePath}`);
96
+ ok(`Config file found: ${configFilePath}`);
91
97
  }
92
98
  else {
93
- console.log(` [--] Config file not found: ${configFilePath} (optional β€” .env fallback used)`);
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
- console.log(` [OK] .env file found: ${env.path}`);
106
+ ok(`.env file found: ${env.path}`);
101
107
  }
102
108
  else {
103
109
  if (!configLoader_1.ConfigLoader.configExists()) {
104
- console.log(` [!!] .env file not found: ${env.path}`);
110
+ fail(`.env file not found: ${env.path}`);
105
111
  allOk = false;
106
112
  }
107
113
  else {
108
- console.log(` [--] .env file not found: ${env.path} (not needed β€” config.json used)`);
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
- console.log(` [OK] ${v.name} is set`);
121
+ ok(`${v.name} is set`);
116
122
  }
117
123
  else {
118
- console.log(` [!!] ${v.name} is NOT set`);
124
+ fail(`${v.name} is NOT set`);
119
125
  allOk = false;
120
126
  }
121
127
  }
122
128
  // 5. CDP port check
123
- console.log('\n Checking CDP ports...');
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
- console.log(` [OK] CDP port ${port} is responding`);
134
+ ok(`CDP port ${port} is responding`);
129
135
  cdpOk = true;
130
136
  }
131
137
  }
132
138
  if (!cdpOk) {
133
- console.log(' [!!] No CDP ports responding');
134
- console.log(' Run: open -a Antigravity --args --remote-debugging-port=9222');
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
- console.log(`\n [OK] Node.js ${nodeVersion}`);
147
+ ok(`Node.js ${nodeVersion}`);
142
148
  }
143
149
  else {
144
- console.log(`\n [!!] Node.js ${nodeVersion} (>= 18.0.0 required)`);
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(' All checks passed!');
156
+ console.log(` ${logger_1.COLORS.green}All checks passed!${logger_1.COLORS.reset}`);
151
157
  }
152
158
  else {
153
- console.log(' Some checks failed. Please fix the issues above.');
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
- async function startAction() {
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
- await (0, bot_1.startBot)().catch((err) => {
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
  });