lazy-gravity 0.6.1 → 0.6.2

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
@@ -184,13 +184,19 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
184
184
  const enqueueGeneral = createSerialTaskQueueForTest('general', monitorTraceId);
185
185
  const enqueueResponse = createSerialTaskQueueForTest('response', monitorTraceId);
186
186
  const enqueueActivity = createSerialTaskQueueForTest('activity', monitorTraceId);
187
+ const logDeliveryError = (scope, error) => {
188
+ const messageText = error instanceof Error ? error.message : String(error);
189
+ logger_1.logger.warn(`[DiscordDelivery:${monitorTraceId}] ${scope} failed: ${messageText}`);
190
+ };
187
191
  const sendEmbed = (title, description, color, fields, footerText) => enqueueGeneral(async () => {
188
192
  if (!channel)
189
193
  return;
190
194
  if (outputFormat === 'plain') {
191
195
  const chunks = (0, plainTextFormatter_1.formatAsPlainText)({ title, description, fields, footerText });
192
196
  for (const chunk of chunks) {
193
- await channel.send({ content: chunk }).catch(() => { });
197
+ await channel.send({ content: chunk }).catch((error) => {
198
+ logDeliveryError('sendEmbed/plain/send', error);
199
+ });
194
200
  }
195
201
  return;
196
202
  }
@@ -205,7 +211,9 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
205
211
  if (footerText) {
206
212
  embed.setFooter({ text: footerText });
207
213
  }
208
- await channel.send({ embeds: [embed] }).catch(() => { });
214
+ await channel.send({ embeds: [embed] }).catch((error) => {
215
+ logDeliveryError('sendEmbed/embed/send', error);
216
+ });
209
217
  }, 'send-embed');
210
218
  const shouldTryGeneratedImages = (inputPrompt, responseText) => {
211
219
  const prompt = (inputPrompt || '').toLowerCase();
@@ -238,7 +246,9 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
238
246
  await channel.send({
239
247
  content: (0, i18n_1.t)(`🖼️ Detected generated images (${files.length})`),
240
248
  files,
241
- }).catch(() => { });
249
+ }).catch((error) => {
250
+ logDeliveryError('sendGeneratedImages/send', error);
251
+ });
242
252
  }, 'send-generated-images');
243
253
  };
244
254
  const tryEmergencyExtractText = async () => {
@@ -322,7 +332,9 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
322
332
  // Apply default model preference on CDP connect
323
333
  const defaultModelResult = await (0, defaultModelApplicator_1.applyDefaultModel)(cdp, modelService);
324
334
  if (defaultModelResult.stale && defaultModelResult.staleMessage && channel) {
325
- await channel.send(defaultModelResult.staleMessage).catch(() => { });
335
+ await channel.send(defaultModelResult.staleMessage).catch((error) => {
336
+ logDeliveryError('defaultModelResult/send', error);
337
+ });
326
338
  }
327
339
  const localMode = modeService.getCurrentMode();
328
340
  const modeName = modeService_1.MODE_UI_NAMES[localMode] || localMode;
@@ -383,11 +395,18 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
383
395
  lastLiveResponseKey = renderKey;
384
396
  for (let i = 0; i < plainChunks.length; i++) {
385
397
  if (!liveResponseMessages[i]) {
386
- liveResponseMessages[i] = await channel.send({ content: plainChunks[i] }).catch(() => null);
398
+ liveResponseMessages[i] = await channel.send({ content: plainChunks[i] }).catch((error) => {
399
+ logDeliveryError('liveResponse/plain/send', error);
400
+ return null;
401
+ });
387
402
  continue;
388
403
  }
389
- await liveResponseMessages[i].edit({ content: plainChunks[i] }).catch(async () => {
390
- liveResponseMessages[i] = await channel.send({ content: plainChunks[i] }).catch(() => null);
404
+ await liveResponseMessages[i].edit({ content: plainChunks[i] }).catch(async (error) => {
405
+ logDeliveryError('liveResponse/plain/edit', error);
406
+ liveResponseMessages[i] = await channel.send({ content: plainChunks[i] }).catch((sendError) => {
407
+ logDeliveryError('liveResponse/plain/resend', sendError);
408
+ return null;
409
+ });
391
410
  });
392
411
  }
393
412
  while (liveResponseMessages.length > plainChunks.length) {
@@ -412,11 +431,18 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
412
431
  .setFooter({ text: footerText })
413
432
  .setTimestamp();
414
433
  if (!liveResponseMessages[i]) {
415
- liveResponseMessages[i] = await channel.send({ embeds: [embed] }).catch(() => null);
434
+ liveResponseMessages[i] = await channel.send({ embeds: [embed] }).catch((error) => {
435
+ logDeliveryError('liveResponse/embed/send', error);
436
+ return null;
437
+ });
416
438
  continue;
417
439
  }
418
- await liveResponseMessages[i].edit({ embeds: [embed] }).catch(async () => {
419
- liveResponseMessages[i] = await channel.send({ embeds: [embed] }).catch(() => null);
440
+ await liveResponseMessages[i].edit({ embeds: [embed] }).catch(async (error) => {
441
+ logDeliveryError('liveResponse/embed/edit', error);
442
+ liveResponseMessages[i] = await channel.send({ embeds: [embed] }).catch((sendError) => {
443
+ logDeliveryError('liveResponse/embed/resend', sendError);
444
+ return null;
445
+ });
420
446
  });
421
447
  }
422
448
  // Delete excess messages if page count decreased
@@ -444,11 +470,18 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
444
470
  lastLiveActivityKey = renderKey;
445
471
  for (let i = 0; i < plainChunks.length; i++) {
446
472
  if (!liveActivityMessages[i]) {
447
- liveActivityMessages[i] = await channel.send({ content: plainChunks[i] }).catch(() => null);
473
+ liveActivityMessages[i] = await channel.send({ content: plainChunks[i] }).catch((error) => {
474
+ logDeliveryError('liveActivity/plain/send', error);
475
+ return null;
476
+ });
448
477
  continue;
449
478
  }
450
- await liveActivityMessages[i].edit({ content: plainChunks[i] }).catch(async () => {
451
- liveActivityMessages[i] = await channel.send({ content: plainChunks[i] }).catch(() => null);
479
+ await liveActivityMessages[i].edit({ content: plainChunks[i] }).catch(async (error) => {
480
+ logDeliveryError('liveActivity/plain/edit', error);
481
+ liveActivityMessages[i] = await channel.send({ content: plainChunks[i] }).catch((sendError) => {
482
+ logDeliveryError('liveActivity/plain/resend', sendError);
483
+ return null;
484
+ });
452
485
  });
453
486
  }
454
487
  while (liveActivityMessages.length > plainChunks.length) {
@@ -473,11 +506,18 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
473
506
  .setFooter({ text: footerText })
474
507
  .setTimestamp();
475
508
  if (!liveActivityMessages[i]) {
476
- liveActivityMessages[i] = await channel.send({ embeds: [embed] }).catch(() => null);
509
+ liveActivityMessages[i] = await channel.send({ embeds: [embed] }).catch((error) => {
510
+ logDeliveryError('liveActivity/embed/send', error);
511
+ return null;
512
+ });
477
513
  continue;
478
514
  }
479
- await liveActivityMessages[i].edit({ embeds: [embed] }).catch(async () => {
480
- liveActivityMessages[i] = await channel.send({ embeds: [embed] }).catch(() => null);
515
+ await liveActivityMessages[i].edit({ embeds: [embed] }).catch(async (error) => {
516
+ logDeliveryError('liveActivity/embed/edit', error);
517
+ liveActivityMessages[i] = await channel.send({ embeds: [embed] }).catch((sendError) => {
518
+ logDeliveryError('liveActivity/embed/resend', sendError);
519
+ return null;
520
+ });
481
521
  });
482
522
  }
483
523
  while (liveActivityMessages.length > descriptions.length) {
@@ -488,6 +528,7 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
488
528
  }
489
529
  }, `upsert-activity:${opts?.source ?? 'unknown'}`);
490
530
  try {
531
+ const baseline = await (0, responseMonitor_1.captureResponseMonitorBaseline)(cdp);
491
532
  logger_1.logger.prompt(prompt);
492
533
  let injectResult;
493
534
  if (inboundImages.length > 0) {
@@ -516,6 +557,8 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
516
557
  maxDurationMs: options?.responseTimeoutMs,
517
558
  stopGoneConfirmCount: 3,
518
559
  extractionMode: options?.extractionMode,
560
+ initialBaselineText: baseline.text,
561
+ initialSeenProcessLogKeys: baseline.processLogKeys,
519
562
  onPhaseChange: (_phase, _text) => {
520
563
  // Phase transitions are already logged inside ResponseMonitor.setPhase()
521
564
  },
@@ -578,7 +621,9 @@ async function sendPromptToAntigravity(bridge, message, prompt, cdp, modeService
578
621
  try {
579
622
  const modelsPayload = await (0, modelsUi_1.buildModelsUI)(cdp, () => bridge.quota.fetchQuota());
580
623
  if (modelsPayload && channel) {
581
- await channel.send({ ...modelsPayload });
624
+ await channel.send({ ...modelsPayload }).catch((error) => {
625
+ logDeliveryError('quota/modelsPayload/send', error);
626
+ });
582
627
  }
583
628
  }
584
629
  catch (e) {
@@ -155,6 +155,7 @@ function createTelegramMessageHandler(deps) {
155
155
  }
156
156
  // Determine the prompt text — use default for image-only messages
157
157
  const effectivePrompt = promptText || 'Please review the attached images and respond accordingly.';
158
+ const baseline = await (0, responseMonitor_1.captureResponseMonitorBaseline)(cdp);
158
159
  // Inject prompt (with or without images) into Antigravity
159
160
  logger_1.logger.prompt(effectivePrompt);
160
161
  let injectResult;
@@ -208,6 +209,8 @@ function createTelegramMessageHandler(deps) {
208
209
  maxDurationMs: TIMEOUT_MS,
209
210
  stopGoneConfirmCount: 3,
210
211
  extractionMode: deps.extractionMode,
212
+ initialBaselineText: baseline.text,
213
+ initialSeenProcessLogKeys: baseline.processLogKeys,
211
214
  onProcessLog: (logText) => {
212
215
  if (logText && logText.trim().length > 0) {
213
216
  lastActivityLogText = processLogBuffer.append(logText);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResponseMonitor = exports.RESPONSE_SELECTORS = void 0;
4
+ exports.captureResponseMonitorBaseline = captureResponseMonitorBaseline;
4
5
  const logger_1 = require("../utils/logger");
5
6
  const assistantDomExtractor_1 = require("./assistantDomExtractor");
6
7
  /** Lean DOM selectors for response extraction */
@@ -433,6 +434,125 @@ exports.RESPONSE_SELECTORS = {
433
434
  return diag;
434
435
  })()`,
435
436
  };
437
+ /**
438
+ * Prefer the active runtime context first, then fall back to any discovered contexts.
439
+ */
440
+ function getOrderedContextTargets(cdpService) {
441
+ const primaryId = cdpService.getPrimaryContextId?.() ?? null;
442
+ const rawContexts = cdpService.getContexts?.() ?? [];
443
+ const contexts = rawContexts
444
+ .filter((ctx) => ctx && typeof ctx.id === 'number')
445
+ .map((ctx) => ({
446
+ id: ctx.id,
447
+ name: typeof ctx.name === 'string' ? ctx.name : undefined,
448
+ url: typeof ctx.url === 'string' ? ctx.url : undefined,
449
+ }));
450
+ if (contexts.length === 0) {
451
+ return primaryId !== null ? [{ id: primaryId }] : [];
452
+ }
453
+ if (primaryId === null) {
454
+ return contexts;
455
+ }
456
+ const primary = contexts.find((ctx) => ctx.id === primaryId);
457
+ const ordered = primary ? [primary] : [{ id: primaryId }];
458
+ for (const ctx of contexts) {
459
+ if (ctx.id !== primaryId)
460
+ ordered.push(ctx);
461
+ }
462
+ return ordered;
463
+ }
464
+ /**
465
+ * Evaluate an expression across known runtime contexts until one returns an acceptable value.
466
+ */
467
+ async function evaluateAcrossContexts(cdpService, expression, accept, options) {
468
+ const awaitPromise = options?.awaitPromise ?? true;
469
+ const targets = getOrderedContextTargets(cdpService);
470
+ let firstValue = null;
471
+ let lastError = null;
472
+ if (targets.length === 0) {
473
+ const result = await cdpService.call('Runtime.evaluate', {
474
+ expression,
475
+ returnByValue: true,
476
+ awaitPromise,
477
+ });
478
+ return {
479
+ value: (result?.result?.value ?? null),
480
+ contextId: null,
481
+ contextName: null,
482
+ contextUrl: null,
483
+ };
484
+ }
485
+ for (const target of targets) {
486
+ try {
487
+ const result = await cdpService.call('Runtime.evaluate', {
488
+ expression,
489
+ returnByValue: true,
490
+ awaitPromise,
491
+ contextId: target.id,
492
+ });
493
+ const value = (result?.result?.value ?? null);
494
+ const probed = {
495
+ value,
496
+ contextId: target.id,
497
+ contextName: target.name ?? null,
498
+ contextUrl: target.url ?? null,
499
+ };
500
+ if (!firstValue)
501
+ firstValue = probed;
502
+ if (accept(value)) {
503
+ return probed;
504
+ }
505
+ }
506
+ catch (error) {
507
+ lastError = error;
508
+ }
509
+ }
510
+ if (firstValue) {
511
+ return firstValue;
512
+ }
513
+ if (lastError) {
514
+ throw lastError;
515
+ }
516
+ return {
517
+ value: null,
518
+ contextId: null,
519
+ contextName: null,
520
+ contextUrl: null,
521
+ };
522
+ }
523
+ /**
524
+ * Capture the current assistant/output DOM state before sending a new prompt.
525
+ * This avoids races where a fast reply is mistaken for baseline text.
526
+ */
527
+ async function captureResponseMonitorBaseline(cdpService) {
528
+ let text = null;
529
+ try {
530
+ const textResult = await evaluateAcrossContexts(cdpService, exports.RESPONSE_SELECTORS.RESPONSE_TEXT, (value) => typeof value === 'string' && value.trim().length > 0);
531
+ text = typeof textResult.value === 'string' ? textResult.value.trim() || null : null;
532
+ }
533
+ catch {
534
+ text = null;
535
+ }
536
+ const processLogKeys = new Set();
537
+ try {
538
+ const logResult = await evaluateAcrossContexts(cdpService, exports.RESPONSE_SELECTORS.PROCESS_LOGS, (value) => Array.isArray(value) && value.length > 0);
539
+ const logEntries = logResult.value;
540
+ if (Array.isArray(logEntries)) {
541
+ for (const entry of logEntries) {
542
+ const key = String(entry || '').replace(/\r/g, '').trim().slice(0, 200);
543
+ if (key)
544
+ processLogKeys.add(key);
545
+ }
546
+ }
547
+ }
548
+ catch {
549
+ // best-effort baseline capture
550
+ }
551
+ return {
552
+ text,
553
+ processLogKeys: Array.from(processLogKeys),
554
+ };
555
+ }
436
556
  /**
437
557
  * Lean AI response monitor.
438
558
  *
@@ -452,6 +572,8 @@ class ResponseMonitor {
452
572
  onTimeout;
453
573
  onPhaseChange;
454
574
  onProcessLog;
575
+ initialBaselineText;
576
+ initialSeenProcessLogKeys;
455
577
  pollTimer = null;
456
578
  isRunning = false;
457
579
  lastText = null;
@@ -462,6 +584,7 @@ class ResponseMonitor {
462
584
  quotaDetected = false;
463
585
  seenProcessLogKeys = new Set();
464
586
  structuredDiagLogged = false;
587
+ lastContentContextId = null;
465
588
  // CDP disconnect handling (#48)
466
589
  isPaused = false;
467
590
  onCdpDisconnected = null;
@@ -480,6 +603,8 @@ class ResponseMonitor {
480
603
  this.onTimeout = options.onTimeout;
481
604
  this.onPhaseChange = options.onPhaseChange;
482
605
  this.onProcessLog = options.onProcessLog;
606
+ this.initialBaselineText = options.initialBaselineText;
607
+ this.initialSeenProcessLogKeys = options.initialSeenProcessLogKeys;
483
608
  }
484
609
  /** Start monitoring */
485
610
  async start() {
@@ -508,28 +633,38 @@ class ResponseMonitor {
508
633
  this.quotaDetected = false;
509
634
  this.seenProcessLogKeys = new Set();
510
635
  this.onPhaseChange?.(this.currentPhase, null);
511
- // Capture baseline text
512
- try {
513
- const baseResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.RESPONSE_TEXT));
514
- const rawValue = baseResult?.result?.value;
515
- this.baselineText = typeof rawValue === 'string' ? rawValue.trim() || null : null;
516
- }
517
- catch {
518
- this.baselineText = null;
636
+ if (this.initialBaselineText !== undefined) {
637
+ this.baselineText = this.initialBaselineText;
519
638
  }
520
- // Capture baseline process logs as already-seen keys
521
- try {
522
- const logResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.PROCESS_LOGS));
523
- const logEntries = logResult?.result?.value;
524
- if (Array.isArray(logEntries)) {
525
- this.seenProcessLogKeys = new Set(logEntries
526
- .map((s) => (s || '').replace(/\r/g, '').trim())
527
- .filter((s) => s.length > 0)
528
- .map((s) => s.slice(0, 200)));
639
+ else {
640
+ try {
641
+ const baseResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.RESPONSE_TEXT, (value) => typeof value === 'string' && value.trim().length > 0);
642
+ this.baselineText = typeof baseResult.value === 'string' ? baseResult.value.trim() || null : null;
643
+ }
644
+ catch {
645
+ this.baselineText = null;
529
646
  }
530
647
  }
531
- catch {
532
- // baseline capture only
648
+ if (this.initialSeenProcessLogKeys !== undefined) {
649
+ this.seenProcessLogKeys = new Set(this.initialSeenProcessLogKeys
650
+ .map((s) => (s || '').replace(/\r/g, '').trim())
651
+ .filter((s) => s.length > 0)
652
+ .map((s) => s.slice(0, 200)));
653
+ }
654
+ else {
655
+ try {
656
+ const logResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.PROCESS_LOGS, (value) => Array.isArray(value) && value.length > 0);
657
+ const logEntries = logResult.value;
658
+ if (Array.isArray(logEntries)) {
659
+ this.seenProcessLogKeys = new Set(logEntries
660
+ .map((s) => (s || '').replace(/\r/g, '').trim())
661
+ .filter((s) => s.length > 0)
662
+ .map((s) => s.slice(0, 200)));
663
+ }
664
+ }
665
+ catch {
666
+ // baseline capture only
667
+ }
533
668
  }
534
669
  // In structured mode, also capture activity lines from the structured
535
670
  // extraction to align the baseline with polling logic. The PROCESS_LOGS
@@ -538,8 +673,8 @@ class ResponseMonitor {
538
673
  // entries from previous turns leak into the process log as "new" entries.
539
674
  if (this.extractionMode === 'structured') {
540
675
  try {
541
- const structuredBaseline = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.RESPONSE_STRUCTURED));
542
- const baselineClassified = (0, assistantDomExtractor_1.classifyAssistantSegments)(structuredBaseline?.result?.value);
676
+ const structuredBaseline = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.RESPONSE_STRUCTURED, (value) => (0, assistantDomExtractor_1.classifyAssistantSegments)(value).diagnostics.source === 'dom-structured');
677
+ const baselineClassified = (0, assistantDomExtractor_1.classifyAssistantSegments)(structuredBaseline.value);
543
678
  if (baselineClassified.diagnostics.source === 'dom-structured') {
544
679
  for (const line of baselineClassified.activityLines) {
545
680
  const key = (line || '').replace(/\r/g, '').trim().slice(0, 200);
@@ -589,12 +724,15 @@ class ResponseMonitor {
589
724
  /** Click the stop button to interrupt LLM generation */
590
725
  async clickStopButton() {
591
726
  try {
592
- const result = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.CLICK_STOP_BUTTON));
593
- const value = result?.result?.value;
727
+ const result = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.CLICK_STOP_BUTTON, (value) => !!(value && typeof value === 'object' && value.ok));
728
+ const value = result.value;
594
729
  if (this.isRunning) {
595
730
  await this.stop();
596
731
  }
597
- return value ?? { ok: false, error: 'CDP evaluation returned empty' };
732
+ if (value && typeof value.ok === 'boolean') {
733
+ return value;
734
+ }
735
+ return { ok: false, error: 'CDP evaluation returned empty' };
598
736
  }
599
737
  catch (error) {
600
738
  return { ok: false, error: error.message || 'Failed to click stop button' };
@@ -693,17 +831,70 @@ class ResponseMonitor {
693
831
  }
694
832
  }, this.pollIntervalMs);
695
833
  }
696
- buildEvaluateParams(expression) {
697
- const params = {
698
- expression,
699
- returnByValue: true,
834
+ async evaluateAcrossContexts(expression, accept) {
835
+ const result = await evaluateAcrossContexts(this.cdpService, expression, accept, {
700
836
  awaitPromise: true,
701
- };
702
- const contextId = this.cdpService.getPrimaryContextId?.();
703
- if (contextId !== null && contextId !== undefined) {
704
- params.contextId = contextId;
837
+ });
838
+ if (result.contextId !== null
839
+ && accept(result.value)
840
+ && this.lastContentContextId !== result.contextId) {
841
+ this.lastContentContextId = result.contextId;
842
+ logger_1.logger.debug(`[ResponseMonitor] Using context ${result.contextId} (${result.contextName ?? 'unknown'} | ${result.contextUrl ?? 'no-url'})`);
843
+ }
844
+ return result;
845
+ }
846
+ async logStructuredExtractionDiagnostics(payload) {
847
+ try {
848
+ const dumpResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.DUMP_ALL_TEXTS, (value) => Array.isArray(value) && value.length > 0);
849
+ const dumpValue = Array.isArray(dumpResult.value) ? dumpResult.value : [];
850
+ const accepted = dumpValue.filter((entry) => !entry?.skip).slice(0, 5);
851
+ const skipped = dumpValue.filter((entry) => entry?.skip).slice(0, 5);
852
+ logger_1.logger.warn(`[ResponseMonitor:diag] Structured payload invalid — ${dumpValue.length} candidate(s), ` +
853
+ `${accepted.length} accepted, ${skipped.length} skipped ` +
854
+ `(context=${dumpResult.contextId ?? 'none'})`);
855
+ logger_1.logger.debug('[ResponseMonitor:diag] Candidate details:', JSON.stringify({
856
+ payloadType: payload === null ? 'null' : typeof payload,
857
+ contextId: dumpResult.contextId,
858
+ contextUrl: dumpResult.contextUrl,
859
+ totalCandidates: dumpValue.length,
860
+ accepted: accepted.map((entry) => ({
861
+ sel: entry.sel,
862
+ len: entry.len,
863
+ preview: entry.preview,
864
+ })),
865
+ skipped: skipped.map((entry) => ({
866
+ sel: entry.sel,
867
+ skip: entry.skip,
868
+ len: entry.len,
869
+ preview: entry.preview,
870
+ })),
871
+ }));
872
+ }
873
+ catch (error) {
874
+ logger_1.logger.warn('[ResponseMonitor:diag] DUMP_ALL_TEXTS failed:', error);
875
+ }
876
+ try {
877
+ const domResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.DOM_DIAGNOSTIC, (value) => !!value && typeof value === 'object' && (Array.isArray(value.allTextNodes)
878
+ || Array.isArray(value.activityNodes)
879
+ || Array.isArray(value.detailsDump)));
880
+ const domValue = domResult.value;
881
+ logger_1.logger.warn(`[ResponseMonitor:diag] DOM_DIAGNOSTIC — ` +
882
+ `details=${domValue?.detailsCount ?? 0}, ` +
883
+ `activity=${Array.isArray(domValue?.activityNodes) ? domValue.activityNodes.length : 0}, ` +
884
+ `textNodes=${Array.isArray(domValue?.allTextNodes) ? domValue.allTextNodes.length : 0} ` +
885
+ `(context=${domResult.contextId ?? 'none'})`);
886
+ logger_1.logger.debug('[ResponseMonitor:diag] DOM_DIAGNOSTIC details:', JSON.stringify({
887
+ contextId: domResult.contextId,
888
+ contextUrl: domResult.contextUrl,
889
+ detailsCount: domValue?.detailsCount ?? null,
890
+ detailsDump: Array.isArray(domValue?.detailsDump) ? domValue.detailsDump.slice(0, 3) : [],
891
+ activityNodes: Array.isArray(domValue?.activityNodes) ? domValue.activityNodes.slice(0, 5) : [],
892
+ allTextNodes: Array.isArray(domValue?.allTextNodes) ? domValue.allTextNodes.slice(0, 5) : [],
893
+ }));
894
+ }
895
+ catch (error) {
896
+ logger_1.logger.warn('[ResponseMonitor:diag] DOM_DIAGNOSTIC failed:', error);
705
897
  }
706
- return params;
707
898
  }
708
899
  /**
709
900
  * Emit new process log entries, deduplicating against previously seen keys.
@@ -738,20 +929,20 @@ class ResponseMonitor {
738
929
  async poll() {
739
930
  try {
740
931
  // 1. Stop button check
741
- const stopResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.STOP_BUTTON));
742
- const stopValue = stopResult?.result?.value;
932
+ const stopResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.STOP_BUTTON, (value) => !!(value && typeof value === 'object' && value.isGenerating));
933
+ const stopValue = stopResult.value;
743
934
  const isGenerating = !!(stopValue && typeof stopValue === 'object' && stopValue.isGenerating);
744
935
  // 2. Quota error check
745
- const quotaResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.QUOTA_ERROR));
746
- const quotaDetected = quotaResult?.result?.value === true;
936
+ const quotaResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.QUOTA_ERROR, (value) => value === true);
937
+ const quotaDetected = quotaResult.value === true;
747
938
  // 3. Text extraction (structured or legacy)
748
939
  let currentText = null;
749
940
  let structuredHandledLogs = false;
750
941
  if (this.extractionMode === 'structured') {
751
942
  // Structured: use DOM segment extraction with HTML-to-Markdown
752
943
  try {
753
- const structuredResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.RESPONSE_STRUCTURED));
754
- const payload = structuredResult?.result?.value;
944
+ const structuredResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.RESPONSE_STRUCTURED, (value) => (0, assistantDomExtractor_1.classifyAssistantSegments)(value).diagnostics.source === 'dom-structured');
945
+ const payload = structuredResult.value;
755
946
  const classified = (0, assistantDomExtractor_1.classifyAssistantSegments)(payload);
756
947
  if (classified.diagnostics.source === 'dom-structured') {
757
948
  currentText = classified.finalOutputText.trim() || null;
@@ -768,6 +959,7 @@ class ResponseMonitor {
768
959
  else if (!this.structuredDiagLogged) {
769
960
  this.structuredDiagLogged = true;
770
961
  logger_1.logger.warn('[ResponseMonitor:poll] Structured extraction failed — reason:', classified.diagnostics.fallbackReason ?? 'unknown', '| payload type:', typeof payload, '| payload:', payload === null ? 'null' : payload === undefined ? 'undefined' : 'object');
962
+ await this.logStructuredExtractionDiagnostics(payload);
771
963
  }
772
964
  }
773
965
  catch (error) {
@@ -776,19 +968,14 @@ class ResponseMonitor {
776
968
  }
777
969
  // Legacy path (or fallback from structured)
778
970
  if (currentText === null) {
779
- const textResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.RESPONSE_TEXT));
780
- const rawText = textResult?.result?.value;
781
- const exceptionDetail = textResult?.result?.exceptionDetails ?? textResult?.exceptionDetails;
782
- if (exceptionDetail) {
783
- logger_1.logger.warn('[ResponseMonitor:poll] RESPONSE_TEXT threw:', exceptionDetail.text ?? JSON.stringify(exceptionDetail).slice(0, 200));
784
- }
785
- currentText = typeof rawText === 'string' ? rawText.trim() || null : null;
971
+ const textResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.RESPONSE_TEXT, (value) => typeof value === 'string' && value.trim().length > 0);
972
+ currentText = typeof textResult.value === 'string' ? textResult.value.trim() || null : null;
786
973
  }
787
974
  // 4. Process log extraction — always when structured didn't handle it
788
975
  if (!structuredHandledLogs) {
789
976
  try {
790
- const logResult = await this.cdpService.call('Runtime.evaluate', this.buildEvaluateParams(exports.RESPONSE_SELECTORS.PROCESS_LOGS));
791
- const logEntries = logResult?.result?.value;
977
+ const logResult = await this.evaluateAcrossContexts(exports.RESPONSE_SELECTORS.PROCESS_LOGS, (value) => Array.isArray(value) && value.length > 0);
978
+ const logEntries = logResult.value;
792
979
  if (Array.isArray(logEntries)) {
793
980
  this.emitNewProcessLogs(logEntries);
794
981
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazy-gravity",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
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": {