lazy-gravity 0.6.1 → 0.7.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/bot/index.js +416 -45
- package/dist/bot/telegramCommands.js +175 -48
- package/dist/bot/telegramJoinCommand.js +170 -0
- package/dist/bot/telegramMessageHandler.js +27 -7
- package/dist/bot/telegramProjectCommand.js +71 -18
- package/dist/bot/telegramStartupTarget.js +54 -0
- package/dist/commands/chatCommandHandler.js +8 -12
- package/dist/commands/joinCommandHandler.js +16 -10
- package/dist/commands/registerSlashCommands.js +13 -1
- package/dist/commands/workspaceCommandHandler.js +22 -7
- package/dist/database/accountPreferenceRepository.js +29 -0
- package/dist/database/channelPreferenceRepository.js +29 -0
- package/dist/database/chatSessionRepository.js +66 -3
- package/dist/database/telegramBindingRepository.js +13 -0
- package/dist/events/interactionCreateHandler.js +194 -13
- package/dist/events/messageCreateHandler.js +103 -7
- package/dist/handlers/accountSelectAction.js +45 -0
- package/dist/handlers/modelButtonAction.js +13 -0
- package/dist/services/cdpBridgeManager.js +23 -18
- package/dist/services/cdpConnectionPool.js +133 -206
- package/dist/services/chatSessionService.js +199 -16
- package/dist/services/responseMonitor.js +235 -48
- package/dist/services/userMessageDetector.js +4 -4
- package/dist/ui/accountUi.js +60 -0
- package/dist/utils/accountUtils.js +36 -0
- package/dist/utils/cdpPorts.js +97 -2
- package/dist/utils/configLoader.js +14 -0
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.UserMessageDetector = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
4
5
|
const node_crypto_1 = require("node:crypto");
|
|
5
6
|
const logger_1 = require("../utils/logger");
|
|
6
7
|
/**
|
|
@@ -74,10 +75,9 @@ function computeEchoHash(text) {
|
|
|
74
75
|
* Detects user messages posted directly in the Antigravity UI (e.g., from a PC).
|
|
75
76
|
* Follows the ApprovalDetector polling pattern.
|
|
76
77
|
*/
|
|
77
|
-
class UserMessageDetector {
|
|
78
|
+
class UserMessageDetector extends events_1.EventEmitter {
|
|
78
79
|
cdpService;
|
|
79
80
|
pollIntervalMs;
|
|
80
|
-
onUserMessage;
|
|
81
81
|
pollTimer = null;
|
|
82
82
|
isRunning = false;
|
|
83
83
|
/** Hash of the last detected message (for duplicate prevention) */
|
|
@@ -90,9 +90,9 @@ class UserMessageDetector {
|
|
|
90
90
|
/** True during the first poll — seeds existing DOM state without firing callback */
|
|
91
91
|
isPriming = false;
|
|
92
92
|
constructor(options) {
|
|
93
|
+
super();
|
|
93
94
|
this.cdpService = options.cdpService;
|
|
94
95
|
this.pollIntervalMs = options.pollIntervalMs ?? 2000;
|
|
95
|
-
this.onUserMessage = options.onUserMessage;
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Register a message hash as an echo (sent by LazyGravity).
|
|
@@ -207,7 +207,7 @@ class UserMessageDetector {
|
|
|
207
207
|
this.lastDetectedHash = hash;
|
|
208
208
|
this.addToSeenHashes(hash);
|
|
209
209
|
logger_1.logger.debug(`[UserMessageDetector] New message detected: "${preview}..."`);
|
|
210
|
-
this.
|
|
210
|
+
this.emit('message', info);
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
catch (error) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ACCOUNT_SELECT_ID = void 0;
|
|
4
|
+
exports.buildAccountPayload = buildAccountPayload;
|
|
5
|
+
exports.sendAccountUI = sendAccountUI;
|
|
6
|
+
const discord_js_1 = require("discord.js");
|
|
7
|
+
const richContentBuilder_1 = require("../platform/richContentBuilder");
|
|
8
|
+
exports.ACCOUNT_SELECT_ID = 'account_select';
|
|
9
|
+
function buildAccountPayload(currentAccount, accountNames) {
|
|
10
|
+
const names = accountNames.length > 0 ? accountNames : ['default'];
|
|
11
|
+
const rc = (0, richContentBuilder_1.withTimestamp)((0, richContentBuilder_1.withFooter)((0, richContentBuilder_1.withDescription)((0, richContentBuilder_1.withColor)((0, richContentBuilder_1.withTitle)((0, richContentBuilder_1.createRichContent)(), 'Account Management'), 0x57F287), `**Current Account:** ${currentAccount}\n\n` +
|
|
12
|
+
`**Available Accounts (${names.length})**\n` +
|
|
13
|
+
names.map((name) => {
|
|
14
|
+
const icon = name === currentAccount ? '[x]' : '[ ]';
|
|
15
|
+
return `${icon} **${name}**`;
|
|
16
|
+
}).join('\n')), 'Select an account from the dropdown below'));
|
|
17
|
+
return {
|
|
18
|
+
richContent: rc,
|
|
19
|
+
components: [
|
|
20
|
+
{
|
|
21
|
+
components: [
|
|
22
|
+
{
|
|
23
|
+
type: 'selectMenu',
|
|
24
|
+
customId: exports.ACCOUNT_SELECT_ID,
|
|
25
|
+
placeholder: 'Select an account...',
|
|
26
|
+
options: names.map((name) => ({
|
|
27
|
+
label: name,
|
|
28
|
+
value: name,
|
|
29
|
+
isDefault: name === currentAccount,
|
|
30
|
+
})),
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function sendAccountUI(target, currentAccount, accountNames) {
|
|
38
|
+
const names = accountNames.length > 0 ? accountNames : ['default'];
|
|
39
|
+
const embed = new discord_js_1.EmbedBuilder()
|
|
40
|
+
.setTitle('Account Management')
|
|
41
|
+
.setColor(0x57F287)
|
|
42
|
+
.setDescription(`**Current Account:** ${currentAccount}\n\n` +
|
|
43
|
+
`**Available Accounts (${names.length})**\n` +
|
|
44
|
+
names.map((name) => {
|
|
45
|
+
const icon = name === currentAccount ? '[x]' : '[ ]';
|
|
46
|
+
return `${icon} **${name}**`;
|
|
47
|
+
}).join('\n'))
|
|
48
|
+
.setFooter({ text: 'Select an account from the dropdown below' })
|
|
49
|
+
.setTimestamp();
|
|
50
|
+
const selectMenu = new discord_js_1.StringSelectMenuBuilder()
|
|
51
|
+
.setCustomId(exports.ACCOUNT_SELECT_ID)
|
|
52
|
+
.setPlaceholder('Select an account...')
|
|
53
|
+
.addOptions(names.map((name) => ({
|
|
54
|
+
label: name,
|
|
55
|
+
value: name,
|
|
56
|
+
default: name === currentAccount,
|
|
57
|
+
})));
|
|
58
|
+
const row = new discord_js_1.ActionRowBuilder().addComponents(selectMenu);
|
|
59
|
+
await target.editReply({ content: '', embeds: [embed], components: [row] });
|
|
60
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveValidAccountName = resolveValidAccountName;
|
|
4
|
+
exports.listAccountNames = listAccountNames;
|
|
5
|
+
exports.inferParentScopeChannelId = inferParentScopeChannelId;
|
|
6
|
+
exports.resolveScopedAccountName = resolveScopedAccountName;
|
|
7
|
+
function resolveValidAccountName(requested, accounts) {
|
|
8
|
+
const safeAccounts = accounts && accounts.length > 0 ? accounts : [{ name: 'default', cdpPort: 9222 }];
|
|
9
|
+
if (!requested)
|
|
10
|
+
return safeAccounts[0].name;
|
|
11
|
+
return safeAccounts.some((account) => account.name === requested) ? requested : safeAccounts[0].name;
|
|
12
|
+
}
|
|
13
|
+
function listAccountNames(accounts) {
|
|
14
|
+
const safeAccounts = accounts && accounts.length > 0 ? accounts : [{ name: 'default', cdpPort: 9222 }];
|
|
15
|
+
return safeAccounts.map((account) => account.name);
|
|
16
|
+
}
|
|
17
|
+
function inferParentScopeChannelId(channelId, explicitParentChannelId) {
|
|
18
|
+
if (explicitParentChannelId && explicitParentChannelId.trim().length > 0) {
|
|
19
|
+
return explicitParentChannelId.trim();
|
|
20
|
+
}
|
|
21
|
+
const underscoreIndex = channelId.indexOf('_');
|
|
22
|
+
if (underscoreIndex > 0) {
|
|
23
|
+
return channelId.slice(0, underscoreIndex);
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function resolveScopedAccountName(options) {
|
|
28
|
+
const parentChannelId = inferParentScopeChannelId(options.channelId, options.parentChannelId);
|
|
29
|
+
return resolveValidAccountName(options.sessionAccountName
|
|
30
|
+
?? options.selectedAccountByChannel?.get(options.channelId)
|
|
31
|
+
?? options.channelPrefRepo?.getAccountName(options.channelId)
|
|
32
|
+
?? (parentChannelId ? options.selectedAccountByChannel?.get(parentChannelId) : null)
|
|
33
|
+
?? (parentChannelId ? options.channelPrefRepo?.getAccountName(parentChannelId) : null)
|
|
34
|
+
?? options.accountPrefRepo?.getAccountName(options.userId)
|
|
35
|
+
?? 'default', options.accounts);
|
|
36
|
+
}
|
package/dist/utils/cdpPorts.js
CHANGED
|
@@ -1,5 +1,100 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CDP_PORTS = void 0;
|
|
3
|
+
exports.CDP_PORTS = exports.DEFAULT_CDP_PORTS = void 0;
|
|
4
|
+
exports.normalizeAntigravityAccounts = normalizeAntigravityAccounts;
|
|
5
|
+
exports.parseAntigravityAccounts = parseAntigravityAccounts;
|
|
6
|
+
exports.serializeAntigravityAccounts = serializeAntigravityAccounts;
|
|
7
|
+
exports.getConfiguredCdpPorts = getConfiguredCdpPorts;
|
|
8
|
+
exports.getAccountPortMap = getAccountPortMap;
|
|
9
|
+
/** Default CDP port list scanned for Antigravity connections. */
|
|
10
|
+
exports.DEFAULT_CDP_PORTS = [9222, 9223, 9333, 9444, 9555, 9666];
|
|
11
|
+
function parsePort(raw) {
|
|
12
|
+
const port = Number(raw);
|
|
13
|
+
if (!Number.isInteger(port))
|
|
14
|
+
return null;
|
|
15
|
+
if (port < 1 || port > 65535)
|
|
16
|
+
return null;
|
|
17
|
+
return port;
|
|
18
|
+
}
|
|
19
|
+
function normalizeAntigravityAccounts(accounts) {
|
|
20
|
+
if (!accounts || accounts.length === 0) {
|
|
21
|
+
return [{ name: 'default', cdpPort: exports.DEFAULT_CDP_PORTS[0] }];
|
|
22
|
+
}
|
|
23
|
+
const seenNames = new Set();
|
|
24
|
+
const normalized = [];
|
|
25
|
+
for (const account of accounts) {
|
|
26
|
+
const name = String(account.name || '').trim();
|
|
27
|
+
const cdpPort = parsePort(String(account.cdpPort));
|
|
28
|
+
if (!name || cdpPort === null || seenNames.has(name))
|
|
29
|
+
continue;
|
|
30
|
+
seenNames.add(name);
|
|
31
|
+
const userDataDir = typeof account.userDataDir === 'string'
|
|
32
|
+
? account.userDataDir.trim()
|
|
33
|
+
: '';
|
|
34
|
+
normalized.push({
|
|
35
|
+
name,
|
|
36
|
+
cdpPort,
|
|
37
|
+
...(userDataDir ? { userDataDir } : {}),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return normalized.length > 0
|
|
41
|
+
? normalized
|
|
42
|
+
: [{ name: 'default', cdpPort: exports.DEFAULT_CDP_PORTS[0] }];
|
|
43
|
+
}
|
|
44
|
+
function parseAntigravityAccounts(rawValue) {
|
|
45
|
+
if (!rawValue || rawValue.trim().length === 0) {
|
|
46
|
+
return [{ name: 'default', cdpPort: exports.DEFAULT_CDP_PORTS[0] }];
|
|
47
|
+
}
|
|
48
|
+
const parsed = rawValue
|
|
49
|
+
.split(',')
|
|
50
|
+
.map((entry) => entry.trim())
|
|
51
|
+
.filter((entry) => entry.length > 0)
|
|
52
|
+
.map((entry) => {
|
|
53
|
+
const colonIndex = entry.indexOf(':');
|
|
54
|
+
if (colonIndex <= 0)
|
|
55
|
+
return null;
|
|
56
|
+
const name = entry.slice(0, colonIndex).trim();
|
|
57
|
+
const rest = entry.slice(colonIndex + 1).trim();
|
|
58
|
+
const atIndex = rest.indexOf('@');
|
|
59
|
+
const portRaw = atIndex >= 0 ? rest.slice(0, atIndex).trim() : rest;
|
|
60
|
+
const userDataDirRaw = atIndex >= 0 ? rest.slice(atIndex + 1).trim() : '';
|
|
61
|
+
const cdpPort = parsePort(portRaw);
|
|
62
|
+
if (!name || cdpPort === null)
|
|
63
|
+
return null;
|
|
64
|
+
return {
|
|
65
|
+
name,
|
|
66
|
+
cdpPort,
|
|
67
|
+
...(userDataDirRaw ? { userDataDir: userDataDirRaw } : {}),
|
|
68
|
+
};
|
|
69
|
+
})
|
|
70
|
+
.filter((account) => account !== null);
|
|
71
|
+
return normalizeAntigravityAccounts(parsed);
|
|
72
|
+
}
|
|
73
|
+
function serializeAntigravityAccounts(accounts) {
|
|
74
|
+
return normalizeAntigravityAccounts(accounts)
|
|
75
|
+
.map((account) => {
|
|
76
|
+
const userDataDir = typeof account.userDataDir === 'string'
|
|
77
|
+
? account.userDataDir.trim()
|
|
78
|
+
: '';
|
|
79
|
+
return userDataDir
|
|
80
|
+
? `${account.name}:${account.cdpPort}@${userDataDir}`
|
|
81
|
+
: `${account.name}:${account.cdpPort}`;
|
|
82
|
+
})
|
|
83
|
+
.join(',');
|
|
84
|
+
}
|
|
85
|
+
function getConfiguredCdpPorts(rawValue) {
|
|
86
|
+
if (!rawValue || rawValue.trim().length === 0) {
|
|
87
|
+
return [...exports.DEFAULT_CDP_PORTS];
|
|
88
|
+
}
|
|
89
|
+
const accounts = parseAntigravityAccounts(rawValue);
|
|
90
|
+
const uniquePorts = new Set();
|
|
91
|
+
for (const account of accounts) {
|
|
92
|
+
uniquePorts.add(account.cdpPort);
|
|
93
|
+
}
|
|
94
|
+
return uniquePorts.size > 0 ? [...uniquePorts] : [...exports.DEFAULT_CDP_PORTS];
|
|
95
|
+
}
|
|
96
|
+
function getAccountPortMap(rawValue) {
|
|
97
|
+
return Object.fromEntries(parseAntigravityAccounts(rawValue).map((account) => [account.name, account.cdpPort]));
|
|
98
|
+
}
|
|
4
99
|
/** CDP port list scanned for Antigravity connections */
|
|
5
|
-
exports.CDP_PORTS =
|
|
100
|
+
exports.CDP_PORTS = exports.DEFAULT_CDP_PORTS;
|
|
@@ -38,6 +38,7 @@ const fs = __importStar(require("fs"));
|
|
|
38
38
|
const os = __importStar(require("os"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const dotenv = __importStar(require("dotenv"));
|
|
41
|
+
const cdpPorts_1 = require("./cdpPorts");
|
|
41
42
|
// Load .env at module init time (same as the original config.ts behavior).
|
|
42
43
|
// dotenv will NOT override already-set env vars by default.
|
|
43
44
|
dotenv.config();
|
|
@@ -103,6 +104,7 @@ function mergeConfig(persisted) {
|
|
|
103
104
|
const logLevel = resolveLogLevel(process.env.LOG_LEVEL, persisted.logLevel);
|
|
104
105
|
const extractionMode = resolveExtractionMode(process.env.EXTRACTION_MODE, persisted.extractionMode);
|
|
105
106
|
const responseTimeoutMs = resolvePositiveInt(process.env.RESPONSE_TIMEOUT_MS, persisted.responseTimeoutMs, 900000);
|
|
107
|
+
const antigravityAccounts = resolveAntigravityAccounts(process.env.ANTIGRAVITY_ACCOUNTS, persisted.antigravityAccounts);
|
|
106
108
|
// Telegram credentials — only required when Telegram is an active platform
|
|
107
109
|
const telegramToken = process.env.TELEGRAM_BOT_TOKEN ?? persisted.telegramToken ?? undefined;
|
|
108
110
|
const telegramAllowedUserIds = resolveTelegramAllowedUserIds(persisted);
|
|
@@ -119,6 +121,7 @@ function mergeConfig(persisted) {
|
|
|
119
121
|
logLevel,
|
|
120
122
|
extractionMode,
|
|
121
123
|
responseTimeoutMs,
|
|
124
|
+
antigravityAccounts,
|
|
122
125
|
telegramToken,
|
|
123
126
|
telegramAllowedUserIds,
|
|
124
127
|
platforms,
|
|
@@ -164,6 +167,17 @@ function resolveTelegramAllowedUserIds(persisted) {
|
|
|
164
167
|
}
|
|
165
168
|
return undefined;
|
|
166
169
|
}
|
|
170
|
+
function resolveAntigravityAccounts(envValue, persistedValue) {
|
|
171
|
+
if (envValue && envValue.trim().length > 0) {
|
|
172
|
+
return (0, cdpPorts_1.parseAntigravityAccounts)(envValue);
|
|
173
|
+
}
|
|
174
|
+
if (typeof persistedValue === 'string' && persistedValue.trim().length > 0) {
|
|
175
|
+
return (0, cdpPorts_1.parseAntigravityAccounts)(persistedValue);
|
|
176
|
+
}
|
|
177
|
+
return Array.isArray(persistedValue)
|
|
178
|
+
? (0, cdpPorts_1.normalizeAntigravityAccounts)(persistedValue)
|
|
179
|
+
: (0, cdpPorts_1.normalizeAntigravityAccounts)(undefined);
|
|
180
|
+
}
|
|
167
181
|
const VALID_PLATFORMS = ['discord', 'telegram'];
|
|
168
182
|
function resolvePlatforms(envValue, persistedValue) {
|
|
169
183
|
if (envValue) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lazy-gravity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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": {
|