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.
@@ -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.onUserMessage(info);
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
+ }
@@ -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 = [9222, 9223, 9333, 9444, 9555, 9666];
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.6.1",
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": {