lazy-gravity 0.5.4 → 0.5.6
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
CHANGED
|
@@ -499,7 +499,7 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
499
499
|
const monitor = new responseMonitor_1.ResponseMonitor({
|
|
500
500
|
cdpService: cdp,
|
|
501
501
|
pollIntervalMs: 2000,
|
|
502
|
-
maxDurationMs:
|
|
502
|
+
maxDurationMs: options?.responseTimeoutMs,
|
|
503
503
|
stopGoneConfirmCount: 3,
|
|
504
504
|
extractionMode: options?.extractionMode,
|
|
505
505
|
onPhaseChange: (_phase, _text) => {
|
|
@@ -663,9 +663,10 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
|
|
|
663
663
|
: lastProgressText;
|
|
664
664
|
const separated = (0, discordFormatter_1.splitOutputAndLogs)(timeoutText || '');
|
|
665
665
|
const sanitizedTimeoutLogs = lastActivityLogText || processLogBuffer.snapshot();
|
|
666
|
+
const timeoutMinutes = Math.round((options?.responseTimeoutMs ?? 900000) / 60000);
|
|
666
667
|
const payload = separated.output && separated.output.trim().length > 0
|
|
667
|
-
? (0, i18n_1.t)(`${separated.output}\n\n[Monitor Ended] Timeout after
|
|
668
|
-
:
|
|
668
|
+
? (0, i18n_1.t)(`${separated.output}\n\n[Monitor Ended] Timeout after ${timeoutMinutes} minutes of inactivity.`)
|
|
669
|
+
: `Monitor ended after ${timeoutMinutes} minutes of inactivity. No text was retrieved.`;
|
|
669
670
|
liveResponseUpdateVersion += 1;
|
|
670
671
|
const responseVersion = liveResponseUpdateVersion;
|
|
671
672
|
await upsertLiveResponseEmbeds(`${PHASE_ICONS.timeout} Timeout`, payload, PHASE_COLORS.timeout, `⏱️ Elapsed: ${elapsed}s | Timeout`, {
|
|
@@ -774,7 +775,7 @@ const startBot = async (cliLogLevel) => {
|
|
|
774
775
|
discord_js_1.GatewayIntentBits.MessageContent,
|
|
775
776
|
]
|
|
776
777
|
});
|
|
777
|
-
const joinHandler = new joinCommandHandler_1.JoinCommandHandler(chatSessionService, chatSessionRepo, workspaceBindingRepo, channelManager, bridge.pool, workspaceService, client, config.extractionMode);
|
|
778
|
+
const joinHandler = new joinCommandHandler_1.JoinCommandHandler(chatSessionService, chatSessionRepo, workspaceBindingRepo, channelManager, bridge.pool, workspaceService, client, config.extractionMode, config.responseTimeoutMs);
|
|
778
779
|
client.once(discord_js_1.Events.ClientReady, async (readyClient) => {
|
|
779
780
|
logger_1.logger.info(`Ready! Logged in as ${readyClient.user.tag} | extractionMode=${config.extractionMode}`);
|
|
780
781
|
try {
|
|
@@ -969,6 +970,7 @@ const startBot = async (cliLogLevel) => {
|
|
|
969
970
|
botToken: config.telegramToken,
|
|
970
971
|
botApi: telegramBot.api,
|
|
971
972
|
chatSessionService,
|
|
973
|
+
responseTimeoutMs: config.responseTimeoutMs,
|
|
972
974
|
});
|
|
973
975
|
// Compose select handlers: project select + mode select
|
|
974
976
|
const projectSelectHandler = (0, telegramProjectCommand_1.createTelegramSelectHandler)({
|
|
@@ -192,7 +192,7 @@ function createTelegramMessageHandler(deps) {
|
|
|
192
192
|
// Send initial status message
|
|
193
193
|
statusMsg = await channel.send({ text: 'Processing...' }).catch(() => null);
|
|
194
194
|
await new Promise((resolve) => {
|
|
195
|
-
const TIMEOUT_MS =
|
|
195
|
+
const TIMEOUT_MS = deps.responseTimeoutMs ?? 900_000;
|
|
196
196
|
let settled = false;
|
|
197
197
|
const settle = () => {
|
|
198
198
|
if (settled)
|
|
@@ -24,9 +24,10 @@ class JoinCommandHandler {
|
|
|
24
24
|
workspaceService;
|
|
25
25
|
client;
|
|
26
26
|
extractionMode;
|
|
27
|
+
responseTimeoutMs;
|
|
27
28
|
/** Active ResponseMonitors per workspace (for AI response mirroring) */
|
|
28
29
|
activeResponseMonitors = new Map();
|
|
29
|
-
constructor(chatSessionService, chatSessionRepo, bindingRepo, channelManager, pool, workspaceService, client, extractionMode) {
|
|
30
|
+
constructor(chatSessionService, chatSessionRepo, bindingRepo, channelManager, pool, workspaceService, client, extractionMode, responseTimeoutMs) {
|
|
30
31
|
this.chatSessionService = chatSessionService;
|
|
31
32
|
this.chatSessionRepo = chatSessionRepo;
|
|
32
33
|
this.bindingRepo = bindingRepo;
|
|
@@ -35,6 +36,7 @@ class JoinCommandHandler {
|
|
|
35
36
|
this.workspaceService = workspaceService;
|
|
36
37
|
this.client = client;
|
|
37
38
|
this.extractionMode = extractionMode;
|
|
39
|
+
this.responseTimeoutMs = responseTimeoutMs;
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
42
|
* Resolve a project name (from DB) to its full absolute path.
|
|
@@ -282,7 +284,7 @@ class JoinCommandHandler {
|
|
|
282
284
|
const monitor = new responseMonitor_1.ResponseMonitor({
|
|
283
285
|
cdpService: cdp,
|
|
284
286
|
pollIntervalMs: 2000,
|
|
285
|
-
maxDurationMs:
|
|
287
|
+
maxDurationMs: this.responseTimeoutMs,
|
|
286
288
|
extractionMode: this.extractionMode,
|
|
287
289
|
onComplete: (finalText) => {
|
|
288
290
|
this.activeResponseMonitors.delete(projectName);
|
|
@@ -118,6 +118,7 @@ function createMessageCreateHandler(deps) {
|
|
|
118
118
|
titleGenerator: deps.titleGenerator,
|
|
119
119
|
userPrefRepo: deps.userPrefRepo,
|
|
120
120
|
extractionMode: deps.config.extractionMode,
|
|
121
|
+
responseTimeoutMs: deps.config.responseTimeoutMs,
|
|
121
122
|
});
|
|
122
123
|
}
|
|
123
124
|
else {
|
|
@@ -177,12 +178,37 @@ function createMessageCreateHandler(deps) {
|
|
|
177
178
|
registerApprovalSessionChannel(deps.bridge, projectName, session.displayName, platformChannel);
|
|
178
179
|
}
|
|
179
180
|
if (session?.isRenamed && session.displayName) {
|
|
180
|
-
|
|
181
|
+
let activationResult = await deps.chatSessionService.activateSessionByTitle(cdp, session.displayName);
|
|
181
182
|
if (!activationResult.ok) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
// Recovery: Antigravity may have renamed the session.
|
|
184
|
+
// Check if the currently active chat is the renamed version.
|
|
185
|
+
const currentInfo = await deps.chatSessionService.getCurrentSessionInfo(cdp);
|
|
186
|
+
const isRecoverable = currentInfo.hasActiveChat
|
|
187
|
+
&& currentInfo.title.trim() !== ''
|
|
188
|
+
&& currentInfo.title !== session.displayName;
|
|
189
|
+
if (isRecoverable) {
|
|
190
|
+
const siblings = deps.chatSessionRepo.findByCategoryId(session.categoryId);
|
|
191
|
+
const ownedByOther = siblings.some((s) => s.channelId !== message.channelId
|
|
192
|
+
&& s.displayName === currentInfo.title);
|
|
193
|
+
if (!ownedByOther) {
|
|
194
|
+
const recoveredTitle = currentInfo.title;
|
|
195
|
+
const retryResult = await deps.chatSessionService.activateSessionByTitle(cdp, recoveredTitle);
|
|
196
|
+
if (retryResult.ok) {
|
|
197
|
+
logger_1.logger.info(`[SessionRecovery] Adopting renamed title: ` +
|
|
198
|
+
`"${session.displayName}" -> "${recoveredTitle}" ` +
|
|
199
|
+
`(channel: ${message.channelId})`);
|
|
200
|
+
deps.chatSessionRepo.updateDisplayName(message.channelId, recoveredTitle);
|
|
201
|
+
registerApprovalSessionChannel(deps.bridge, projectName, recoveredTitle, platformChannel);
|
|
202
|
+
}
|
|
203
|
+
activationResult = retryResult;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (!activationResult.ok) {
|
|
207
|
+
const reason = activationResult.error ? ` (${activationResult.error})` : '';
|
|
208
|
+
await message.reply(`⚠️ Could not route this message to the bound session (${session.displayName}). ` +
|
|
209
|
+
`Please open /chat and verify the session${reason}.`).catch(() => { });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
186
212
|
}
|
|
187
213
|
}
|
|
188
214
|
else if (session && !session.isRenamed) {
|
|
@@ -238,6 +264,7 @@ function createMessageCreateHandler(deps) {
|
|
|
238
264
|
titleGenerator: deps.titleGenerator,
|
|
239
265
|
userPrefRepo: deps.userPrefRepo,
|
|
240
266
|
extractionMode: deps.config.extractionMode,
|
|
267
|
+
responseTimeoutMs: deps.config.responseTimeoutMs,
|
|
241
268
|
onFullCompletion: settle,
|
|
242
269
|
}).catch((err) => {
|
|
243
270
|
// sendPromptToAntigravity rejected before onFullCompletion fired
|
|
@@ -472,7 +472,7 @@ class ResponseMonitor {
|
|
|
472
472
|
constructor(options) {
|
|
473
473
|
this.cdpService = options.cdpService;
|
|
474
474
|
this.pollIntervalMs = options.pollIntervalMs ?? 2000;
|
|
475
|
-
this.maxDurationMs = options.maxDurationMs ??
|
|
475
|
+
this.maxDurationMs = options.maxDurationMs ?? 900000;
|
|
476
476
|
this.stopGoneConfirmCount = options.stopGoneConfirmCount ?? 3;
|
|
477
477
|
this.extractionMode = options.extractionMode ?? 'structured';
|
|
478
478
|
this.onProgress = options.onProgress;
|
|
@@ -861,7 +861,10 @@ class ResponseMonitor {
|
|
|
861
861
|
}
|
|
862
862
|
}
|
|
863
863
|
// Activity-based inactivity timeout (#49)
|
|
864
|
-
|
|
864
|
+
// Guard: never timeout while the stop button is visible — it means
|
|
865
|
+
// Antigravity is still actively generating (extended thinking, long
|
|
866
|
+
// shell commands, large file operations, etc.).
|
|
867
|
+
if (this.maxDurationMs > 0 && !isGenerating && Date.now() - this.lastActivityTime >= this.maxDurationMs) {
|
|
865
868
|
const lastText = this.lastText ?? '';
|
|
866
869
|
this.setPhase('timeout', lastText);
|
|
867
870
|
await this.stop();
|
|
@@ -102,6 +102,7 @@ function mergeConfig(persisted) {
|
|
|
102
102
|
const autoApproveFileEdits = resolveBoolean(process.env.AUTO_APPROVE_FILE_EDITS, persisted.autoApproveFileEdits, false);
|
|
103
103
|
const logLevel = resolveLogLevel(process.env.LOG_LEVEL, persisted.logLevel);
|
|
104
104
|
const extractionMode = resolveExtractionMode(process.env.EXTRACTION_MODE, persisted.extractionMode);
|
|
105
|
+
const responseTimeoutMs = resolvePositiveInt(process.env.RESPONSE_TIMEOUT_MS, persisted.responseTimeoutMs, 900000);
|
|
105
106
|
// Telegram credentials — only required when Telegram is an active platform
|
|
106
107
|
const telegramToken = process.env.TELEGRAM_BOT_TOKEN ?? persisted.telegramToken ?? undefined;
|
|
107
108
|
const telegramAllowedUserIds = resolveTelegramAllowedUserIds(persisted);
|
|
@@ -117,6 +118,7 @@ function mergeConfig(persisted) {
|
|
|
117
118
|
autoApproveFileEdits,
|
|
118
119
|
logLevel,
|
|
119
120
|
extractionMode,
|
|
121
|
+
responseTimeoutMs,
|
|
120
122
|
telegramToken,
|
|
121
123
|
telegramAllowedUserIds,
|
|
122
124
|
platforms,
|
|
@@ -186,6 +188,20 @@ function resolveBoolean(envValue, persistedValue, defaultValue) {
|
|
|
186
188
|
return persistedValue;
|
|
187
189
|
return defaultValue;
|
|
188
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Resolve a non-negative integer value from env var > persisted config > default.
|
|
193
|
+
* Returns the default if the env/persisted value is not a valid non-negative integer.
|
|
194
|
+
*/
|
|
195
|
+
function resolvePositiveInt(envValue, persistedValue, defaultValue) {
|
|
196
|
+
if (envValue !== undefined) {
|
|
197
|
+
const parsed = parseInt(envValue, 10);
|
|
198
|
+
if (!isNaN(parsed) && parsed >= 0)
|
|
199
|
+
return parsed;
|
|
200
|
+
}
|
|
201
|
+
if (persistedValue !== undefined && persistedValue >= 0)
|
|
202
|
+
return persistedValue;
|
|
203
|
+
return defaultValue;
|
|
204
|
+
}
|
|
189
205
|
// ---------------------------------------------------------------------------
|
|
190
206
|
// Public API (ConfigLoader namespace)
|
|
191
207
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lazy-gravity",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
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": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@types/ws": "^8.18.1",
|
|
66
66
|
"jest": "^30.2.0",
|
|
67
67
|
"jest-environment-jsdom": "^30.2.0",
|
|
68
|
-
"jsdom": "^
|
|
68
|
+
"jsdom": "^29.0.0",
|
|
69
69
|
"minimatch": "^10.2.1",
|
|
70
70
|
"semantic-release": "^25.0.3",
|
|
71
71
|
"ts-jest": "^29.4.6",
|