lazy-gravity 0.9.2 → 0.11.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 (41) hide show
  1. package/dist/bin/commands/doctor.js +45 -7
  2. package/dist/bot/index.js +401 -41
  3. package/dist/bot/telegramMessageHandler.js +1 -0
  4. package/dist/commands/chatCommandHandler.js +43 -3
  5. package/dist/commands/registerSlashCommands.js +13 -1
  6. package/dist/events/interactionCreateHandler.js +456 -27
  7. package/dist/events/messageCreateHandler.js +66 -7
  8. package/dist/handlers/__tests__/fileChangeButtonAction.test.js +85 -0
  9. package/dist/handlers/approvalButtonAction.js +2 -1
  10. package/dist/handlers/errorPopupButtonAction.js +2 -1
  11. package/dist/handlers/fileChangeButtonAction.js +57 -0
  12. package/dist/handlers/genericActionButtonAction.js +72 -0
  13. package/dist/handlers/planningButtonAction.js +126 -23
  14. package/dist/handlers/planningModalSubmitAction.js +38 -0
  15. package/dist/handlers/questionSelectAction.js +70 -0
  16. package/dist/handlers/questionSkipAction.js +68 -0
  17. package/dist/handlers/runCommandButtonAction.js +2 -1
  18. package/dist/platform/discord/discordResponseRenderer.js +164 -0
  19. package/dist/platform/discord/wrappers.js +76 -0
  20. package/dist/services/approvalDetector.js +110 -35
  21. package/dist/services/artifactService.js +103 -37
  22. package/dist/services/assistantDomExtractor.js +194 -3
  23. package/dist/services/cdpBridgeManager.js +149 -8
  24. package/dist/services/cdpConnectionPool.js +22 -2
  25. package/dist/services/cdpService.js +134 -15
  26. package/dist/services/chatSessionService.js +147 -40
  27. package/dist/services/errorPopupDetector.js +23 -11
  28. package/dist/services/notificationSender.js +80 -3
  29. package/dist/services/planningDetector.js +69 -25
  30. package/dist/services/promptDispatcher.js +27 -1
  31. package/dist/services/questionDetector.js +428 -0
  32. package/dist/services/responseMonitor.js +45 -3
  33. package/dist/services/runCommandDetector.js +14 -7
  34. package/dist/ui/artifactsUi.js +4 -3
  35. package/dist/utils/consecutiveEmptyPollGate.js +21 -0
  36. package/dist/utils/fileOpenCache.js +29 -0
  37. package/dist/utils/htmlToDiscordMarkdown.js +5 -2
  38. package/dist/utils/pathUtils.js +12 -0
  39. package/dist/utils/projectResolver.js +10 -0
  40. package/dist/utils/questionActionUtils.js +47 -0
  41. package/package.json +1 -1
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConsecutiveEmptyPollGate = void 0;
4
+ class ConsecutiveEmptyPollGate {
5
+ requiredEmptyPolls;
6
+ count = 0;
7
+ constructor(requiredEmptyPolls = 3) {
8
+ this.requiredEmptyPolls = requiredEmptyPolls;
9
+ }
10
+ recordDetection() {
11
+ this.count = 0;
12
+ }
13
+ recordEmptyPoll() {
14
+ this.count++;
15
+ return this.count >= this.requiredEmptyPolls;
16
+ }
17
+ reset() {
18
+ this.count = 0;
19
+ }
20
+ }
21
+ exports.ConsecutiveEmptyPollGate = ConsecutiveEmptyPollGate;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fileOpenCache = void 0;
4
+ /**
5
+ * In-memory cache to map button customIds to file URLs.
6
+ * Bounded to a maximum size to prevent memory leaks, using a FIFO eviction policy when the cache size limit is reached.
7
+ */
8
+ class BoundedCache {
9
+ max_size;
10
+ map;
11
+ constructor(max_size = 1000) {
12
+ this.max_size = max_size;
13
+ this.map = new Map();
14
+ }
15
+ set(key, value) {
16
+ if (this.map.size >= this.max_size) {
17
+ // Remove the oldest entry (first item in the map's insertion order)
18
+ const firstKey = this.map.keys().next().value;
19
+ if (firstKey !== undefined) {
20
+ this.map.delete(firstKey);
21
+ }
22
+ }
23
+ this.map.set(key, value);
24
+ }
25
+ get(key) {
26
+ return this.map.get(key);
27
+ }
28
+ }
29
+ exports.fileOpenCache = new BoundedCache(1000);
@@ -42,6 +42,9 @@ function htmlToDiscordMarkdown(html) {
42
42
  // Extract language from class="language-xxx" if present.
43
43
  // Do NOT decode entities here — let the final decodeEntities() handle them
44
44
  // after stripTags() has run, to avoid decoded < > being stripped as tags.
45
+ // First, Antigravity 2.0 wrapped code blocks
46
+ result = result.replace(/<div[^>]*class="[^"]*code-block[^"]*"[^>]*>(?:(?!<div[^>]*class="[^"]*code-block[^"]*"[^>]*>)[\s\S])*?<div[^>]*class="[^"]*code-header[^"]*"[^>]*>([\s\S]*?)<\/div>(?:(?!<div[^>]*class="[^"]*code-block[^"]*"[^>]*>)[\s\S])*?<pre[^>]*>\s*<code[^>]*>([\s\S]*?)<\/code>\s*<\/pre>(?:(?!<div[^>]*class="[^"]*code-block[^"]*"[^>]*>)[\s\S])*?<\/div>/gi, (_m, lang, content) => `\n\`\`\`${stripTags(lang).trim()}\n${content}\n\`\`\`\n`);
47
+ // Standard <pre><code> blocks
45
48
  result = result.replace(/<pre[^>]*>\s*<code(?:\s+class="language-([^"]*)")?[^>]*>([\s\S]*?)<\/code>\s*<\/pre>/gi, (_m, lang, content) => `\n\`\`\`${lang || ''}\n${content}\n\`\`\`\n`);
46
49
  // Handle inline <code>
47
50
  result = result.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, '`$1`');
@@ -49,8 +52,8 @@ function htmlToDiscordMarkdown(html) {
49
52
  result = result.replace(/<(?:strong|b)(?:\s[^>]*)?>((?: |\s|[^<]|<(?!\/(?:strong|b)>))*)<\/(?:strong|b)>/gi, '**$1**');
50
53
  // Handle <em> and <i>
51
54
  result = result.replace(/<(?:em|i)(?:\s[^>]*)?>((?: |\s|[^<]|<(?!\/(?:em|i)>))*)<\/(?:em|i)>/gi, '*$1*');
52
- // Handle <span class="context-scope-mention"> → `text`
53
- result = result.replace(/<span[^>]*class="[^"]*context-scope-mention[^"]*"[^>]*>([\s\S]*?)<\/span>/gi, (_m, text) => `\`${stripTags(text).trim()}\``);
55
+ // Handle <span class="context-scope-mention"> or <span class="file-chip"> → `text`
56
+ result = result.replace(/<span[^>]*class="[^"]*(?:context-scope-mention|file-chip)[^"]*"[^>]*>([\s\S]*?)<\/span>/gi, (_m, text) => `\`${stripTags(text).trim()}\``);
54
57
  // Handle elements with title attribute containing file paths
55
58
  // e.g. <div title="src/bot/index.ts">:54</div> → src/bot/index.ts:54
56
59
  result = result.replace(/<(?:div|span|a)[^>]*\btitle="([^"]*)"[^>]*>([\s\S]*?)<\/(?:div|span|a)>/gi, (_m, title, text) => {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAntigravityCliPath = getAntigravityCliPath;
4
4
  exports.extractProjectNameFromPath = extractProjectNameFromPath;
5
5
  exports.getAntigravityCdpHint = getAntigravityCdpHint;
6
+ exports.getWorkspaceDirName = getWorkspaceDirName;
6
7
  /**
7
8
  * Helper to resolve the correct Antigravity CLI executable path based on the operating system
8
9
  * and environment variables.
@@ -55,3 +56,14 @@ function getAntigravityCdpHint(port = 9222) {
55
56
  return `${APP_NAME.toLowerCase()} --remote-debugging-port=${port}`;
56
57
  }
57
58
  }
59
+ /**
60
+ * Extracts the workspace directory name from a chat session.
61
+ * @param session The chat session object
62
+ * @returns The base directory name, or undefined
63
+ */
64
+ function getWorkspaceDirName(session) {
65
+ if (session && session.workspacePath) {
66
+ return extractProjectNameFromPath(session.workspacePath);
67
+ }
68
+ return undefined;
69
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveProjectName = resolveProjectName;
4
+ function resolveProjectName(deps, channelId, providedProjectName) {
5
+ if (providedProjectName) {
6
+ return providedProjectName;
7
+ }
8
+ const workspacePath = deps.wsHandler.getWorkspaceForChannel(channelId);
9
+ return workspacePath ? deps.bridge.pool.extractProjectName(workspacePath) : undefined;
10
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseQuestionCustomId = parseQuestionCustomId;
4
+ exports.executeBrowserClick = executeBrowserClick;
5
+ const logger_1 = require("./logger");
6
+ const approvalDetector_1 = require("../services/approvalDetector");
7
+ function parseQuestionCustomId(customId, expectedPrefix) {
8
+ if (customId !== expectedPrefix && !customId.startsWith(expectedPrefix + ':'))
9
+ return null;
10
+ const parts = customId.split(':');
11
+ const result = { action: parts[0] };
12
+ try {
13
+ if (parts.length > 1) {
14
+ result.projectName = decodeURIComponent(parts[1]);
15
+ }
16
+ if (parts.length > 2) {
17
+ result.channelId = decodeURIComponent(parts[2]);
18
+ }
19
+ }
20
+ catch (e) {
21
+ // Fallback in case of malformed URI component from truncation
22
+ if (parts.length > 1)
23
+ result.projectName = parts[1];
24
+ if (parts.length > 2)
25
+ result.channelId = parts[2];
26
+ }
27
+ return result;
28
+ }
29
+ /**
30
+ * Executes a click on an element matching the target text in the IDE.
31
+ * Returns true if the click was successfully dispatched, false otherwise.
32
+ */
33
+ async function executeBrowserClick(cdp, buttonText) {
34
+ try {
35
+ const script = (0, approvalDetector_1.buildClickScript)(buttonText);
36
+ const evalResult = await cdp.call('Runtime.evaluate', {
37
+ expression: script,
38
+ returnByValue: true,
39
+ awaitPromise: true,
40
+ });
41
+ return !!evalResult?.result?.value?.ok;
42
+ }
43
+ catch (error) {
44
+ logger_1.logger.error(`[executeBrowserClick] Error clicking button "${buttonText}":`, error);
45
+ return false;
46
+ }
47
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazy-gravity",
3
- "version": "0.9.2",
3
+ "version": "0.11.0",
4
4
  "description": "Control Antigravity from anywhere — a local, secure bot (Discord + Telegram) that lets you remotely operate Antigravity on your home PC from your smartphone.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {