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.
- package/dist/bin/commands/doctor.js +45 -7
- package/dist/bot/index.js +401 -41
- package/dist/bot/telegramMessageHandler.js +1 -0
- package/dist/commands/chatCommandHandler.js +43 -3
- package/dist/commands/registerSlashCommands.js +13 -1
- package/dist/events/interactionCreateHandler.js +456 -27
- package/dist/events/messageCreateHandler.js +66 -7
- package/dist/handlers/__tests__/fileChangeButtonAction.test.js +85 -0
- package/dist/handlers/approvalButtonAction.js +2 -1
- package/dist/handlers/errorPopupButtonAction.js +2 -1
- package/dist/handlers/fileChangeButtonAction.js +57 -0
- package/dist/handlers/genericActionButtonAction.js +72 -0
- package/dist/handlers/planningButtonAction.js +126 -23
- package/dist/handlers/planningModalSubmitAction.js +38 -0
- package/dist/handlers/questionSelectAction.js +70 -0
- package/dist/handlers/questionSkipAction.js +68 -0
- package/dist/handlers/runCommandButtonAction.js +2 -1
- package/dist/platform/discord/discordResponseRenderer.js +164 -0
- package/dist/platform/discord/wrappers.js +76 -0
- package/dist/services/approvalDetector.js +110 -35
- package/dist/services/artifactService.js +103 -37
- package/dist/services/assistantDomExtractor.js +194 -3
- package/dist/services/cdpBridgeManager.js +149 -8
- package/dist/services/cdpConnectionPool.js +22 -2
- package/dist/services/cdpService.js +134 -15
- package/dist/services/chatSessionService.js +147 -40
- package/dist/services/errorPopupDetector.js +23 -11
- package/dist/services/notificationSender.js +80 -3
- package/dist/services/planningDetector.js +69 -25
- package/dist/services/promptDispatcher.js +27 -1
- package/dist/services/questionDetector.js +428 -0
- package/dist/services/responseMonitor.js +45 -3
- package/dist/services/runCommandDetector.js +14 -7
- package/dist/ui/artifactsUi.js +4 -3
- package/dist/utils/consecutiveEmptyPollGate.js +21 -0
- package/dist/utils/fileOpenCache.js +29 -0
- package/dist/utils/htmlToDiscordMarkdown.js +5 -2
- package/dist/utils/pathUtils.js +12 -0
- package/dist/utils/projectResolver.js +10 -0
- package/dist/utils/questionActionUtils.js +47 -0
- 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) => {
|
package/dist/utils/pathUtils.js
CHANGED
|
@@ -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.
|
|
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": {
|