@lightcone-ai/daemon 0.9.63 → 0.9.65

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightcone-ai/daemon",
3
- "version": "0.9.63",
3
+ "version": "0.9.65",
4
4
  "type": "module",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -41,11 +41,7 @@ export const PLATFORM_CONFIGS = {
41
41
  .map(e => ({ e, r: e.getBoundingClientRect() }))
42
42
  .filter(({ r }) => r.top <= boxRect.top + 120 && r.right >= boxRect.right - 140)
43
43
  .sort((a, b) => (b.r.right + boxRect.top - b.r.top) - (a.r.right + boxRect.top - a.r.top))[0]?.e;
44
- if (corner) {
45
- const target = corner.closest('button, [role="button"], a, div') || corner;
46
- target.click();
47
- return 'corner-qr-icon';
48
- }
44
+ if (corner) return { via: 'corner-qr-icon', rect: corner.getBoundingClientRect().toJSON() };
49
45
  return null;
50
46
  `,
51
47
  getSessionValue: (cookies) =>
@@ -228,24 +224,8 @@ export class BrowserLoginSession {
228
224
  // Try to click the QR scan login tab if present (some platforms default to password login)
229
225
  if (this._config.qrTabSelector) {
230
226
  try {
231
- const selectors = this._config.qrTabSelector;
232
- const qrResult = await this.send('Runtime.evaluate', {
233
- expression: `(function() {
234
- const sels = ${JSON.stringify(selectors)};
235
- for (const s of sels) {
236
- const el = document.querySelector(s);
237
- if (el) { el.click(); return s; }
238
- }
239
- // Also try text-based search
240
- const all = [...document.querySelectorAll('a,button,span,div')];
241
- const el = all.find(e => e.innerText?.trim() === '扫码登录' || e.innerText?.trim() === '二维码登录');
242
- if (el) { el.click(); return 'text:' + el.innerText.trim(); }
243
- ${this._config.qrFallbackScript ?? ''}
244
- return null;
245
- })()`,
246
- returnByValue: true,
247
- });
248
- console.log(`[BrowserLogin][${this._platform}] QR switch result: ${qrResult.result?.value ?? 'not-found'}`);
227
+ const qrResult = await this._switchToQrLogin();
228
+ console.log(`[BrowserLogin][${this._platform}] QR switch result: ${qrResult?.via ?? 'not-found'}`);
249
229
  await sleep(1000);
250
230
  } catch (err) {
251
231
  console.error(`[BrowserLogin][${this._platform}] QR switch failed: ${err.message}`);
@@ -306,6 +286,69 @@ export class BrowserLoginSession {
306
286
  return result.data;
307
287
  }
308
288
 
289
+ async _switchToQrLogin() {
290
+ const selectors = this._config.qrTabSelector ?? [];
291
+ const result = await this.send('Runtime.evaluate', {
292
+ expression: `(function() {
293
+ const visible = (el) => {
294
+ const r = el.getBoundingClientRect();
295
+ const cs = getComputedStyle(el);
296
+ return r.width > 0 && r.height > 0 && cs.display !== 'none' && cs.visibility !== 'hidden';
297
+ };
298
+ const hit = (el, via) => {
299
+ if (!el) return null;
300
+ const target = el.closest('button, [role="button"], a') || el;
301
+ const rect = target.getBoundingClientRect();
302
+ if (rect.width <= 0 || rect.height <= 0) return null;
303
+ return { via, rect: rect.toJSON() };
304
+ };
305
+
306
+ const sels = ${JSON.stringify(selectors)};
307
+ for (const s of sels) {
308
+ const el = document.querySelector(s);
309
+ if (el && visible(el)) return hit(el, s);
310
+ }
311
+
312
+ const textElements = [...document.querySelectorAll('a,button,span,div')].filter(visible);
313
+ const textEl = textElements.find(e => {
314
+ const t = (e.innerText || e.textContent || '').trim();
315
+ return t === '扫码登录' || t === '二维码登录' || t === '扫码';
316
+ });
317
+ const textHit = hit(textEl, textEl ? 'text:' + (textEl.innerText || textEl.textContent || '').trim() : '');
318
+ if (textHit) return textHit;
319
+
320
+ const fallbackHit = (function() {
321
+ ${this._config.qrFallbackScript ?? 'return null;'}
322
+ })();
323
+ if (fallbackHit) return fallbackHit;
324
+
325
+ if (location.hostname.includes('xiaohongshu.com')) {
326
+ return {
327
+ via: 'xhs-calibrated-corner',
328
+ point: {
329
+ x: Math.round(window.innerWidth * 0.897),
330
+ y: Math.round(window.innerHeight * 0.339)
331
+ }
332
+ };
333
+ }
334
+ return null;
335
+ })()`,
336
+ returnByValue: true,
337
+ });
338
+
339
+ const hit = result.result?.value;
340
+ const rect = hit?.rect;
341
+ const point = hit?.point;
342
+ if (!rect && !point) return null;
343
+
344
+ const x = point?.x ?? Math.round(rect.left + rect.width / 2);
345
+ const y = point?.y ?? Math.round(rect.top + rect.height / 2);
346
+ await this.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y }, 5_000);
347
+ await this.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 }, 5_000);
348
+ await this.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 }, 5_000);
349
+ return { via: hit.via, x, y };
350
+ }
351
+
309
352
  async isLoggedIn(baseline) {
310
353
  const result = await this.send('Network.getAllCookies', {});
311
354
  return this._config.isLoggedIn(result.cookies ?? [], baseline);