@lightcone-ai/daemon 0.15.19 → 0.15.22

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,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { randomUUID } from 'crypto';
3
3
  import { spawn } from 'child_process';
4
- import { accessSync, constants as fsConstants } from 'fs';
4
+ import { accessSync, constants as fsConstants, existsSync, readFileSync, rmSync } from 'fs';
5
5
  import http from 'http';
6
6
  import net from 'net';
7
+ import path from 'path';
7
8
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
9
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
10
  import { z } from 'zod';
@@ -86,6 +87,12 @@ class CdpSession {
86
87
  if (!profileDir) throw new Error('LOGIN_REQUIRED:WECHAT_MP_PROFILE_DIR is not configured');
87
88
  const chrome = detectChrome();
88
89
  this._port = await getFreePort();
90
+
91
+ for (const lockFile of ['SingletonLock', 'SingletonCookie', 'SingletonSocket']) {
92
+ const lockPath = path.join(profileDir, lockFile);
93
+ try { if (existsSync(lockPath)) rmSync(lockPath, { force: true }); } catch {}
94
+ }
95
+
89
96
  this._proc = spawn(chrome, [
90
97
  `--remote-debugging-port=${this._port}`,
91
98
  '--no-sandbox',
@@ -96,7 +103,7 @@ class CdpSession {
96
103
  '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
97
104
  `--user-data-dir=${profileDir}`,
98
105
  '--window-size=1280,900',
99
- `${WECHAT_MP_ORIGIN}/cgi-bin/home?t=home/index&lang=zh_CN`,
106
+ 'about:blank',
100
107
  ], { stdio: 'ignore' });
101
108
 
102
109
  for (let i = 0; i < 50; i += 1) {
@@ -112,6 +119,8 @@ class CdpSession {
112
119
  await this.cdp('Page.enable');
113
120
  await this.cdp('Network.enable');
114
121
  await this.cdp('Runtime.enable');
122
+ await this.injectCookies(profileDir);
123
+ await this.navigate(`${WECHAT_MP_ORIGIN}/cgi-bin/home?t=home/index&lang=zh_CN`);
115
124
  }
116
125
 
117
126
  _connectWs(wsUrl) {
@@ -160,6 +169,42 @@ class CdpSession {
160
169
  await sleep(1500);
161
170
  }
162
171
 
172
+ async injectCookies(profileDir) {
173
+ const cookiesFile = path.join(profileDir, 'cookies.json');
174
+ if (!existsSync(cookiesFile)) {
175
+ console.error(`[wechat-mp-fetch] cookies.json not found at ${cookiesFile}`);
176
+ return;
177
+ }
178
+ try {
179
+ const rawCookies = JSON.parse(readFileSync(cookiesFile, 'utf8'));
180
+ const cookies = rawCookies.map(({
181
+ name,
182
+ value,
183
+ domain,
184
+ path: cookiePath,
185
+ secure,
186
+ httpOnly,
187
+ sameSite,
188
+ expires,
189
+ priority,
190
+ }) => {
191
+ const cookie = { name, value };
192
+ if (domain !== undefined) cookie.domain = domain;
193
+ if (cookiePath !== undefined) cookie.path = cookiePath;
194
+ if (secure !== undefined) cookie.secure = secure;
195
+ if (httpOnly !== undefined) cookie.httpOnly = httpOnly;
196
+ if (sameSite !== undefined) cookie.sameSite = sameSite;
197
+ if (expires !== undefined && expires !== -1) cookie.expires = expires;
198
+ if (priority !== undefined) cookie.priority = priority;
199
+ return cookie;
200
+ });
201
+ await this.cdp('Network.setCookies', { cookies });
202
+ console.error(`[wechat-mp-fetch] Injected ${cookies.length} cookies from cookies.json`);
203
+ } catch (error) {
204
+ console.error(`[wechat-mp-fetch] Failed to inject cookies: ${error?.message ?? error}`);
205
+ }
206
+ }
207
+
163
208
  async evalValue(expression) {
164
209
  const result = await this.cdp('Runtime.evaluate', {
165
210
  expression,
@@ -191,7 +236,13 @@ async function ensureLoggedIn() {
191
236
  await cdp.navigate(`${WECHAT_MP_ORIGIN}/cgi-bin/home?t=home/index&lang=zh_CN`);
192
237
  href = await cdp.currentUrl();
193
238
  }
194
- const token = new URL(String(href)).searchParams.get('token') ?? '';
239
+ let token = '';
240
+ for (let i = 0; i < 12; i += 1) {
241
+ href = await cdp.currentUrl().catch(() => href);
242
+ token = new URL(String(href)).searchParams.get('token') ?? '';
243
+ if (token) break;
244
+ await sleep(500);
245
+ }
195
246
  if (!token) {
196
247
  throw new Error('LOGIN_REQUIRED:WeChat MP backend login is required');
197
248
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightcone-ai/daemon",
3
- "version": "0.15.19",
3
+ "version": "0.15.22",
4
4
  "type": "module",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -104,6 +104,59 @@ export const PLATFORM_CONFIGS = {
104
104
  ?? null;
105
105
  return val !== null && val !== baseline;
106
106
  },
107
+ async isPageLoggedIn(session) {
108
+ const result = await session.send('Runtime.evaluate', {
109
+ expression: `(async () => {
110
+ const href = location.href;
111
+ const text = document.body?.innerText || '';
112
+ const token = new URL(href).searchParams.get('token') || '';
113
+ if (!/[?&]token=\\d+/.test(href) || text.includes('登录超时') || text.includes('重新登录')) {
114
+ return {
115
+ href,
116
+ hasToken: Boolean(token),
117
+ loginTimedOut: text.includes('登录超时') || text.includes('重新登录'),
118
+ apiOk: false
119
+ };
120
+ }
121
+
122
+ const url = new URL('/cgi-bin/searchbiz', location.origin);
123
+ url.searchParams.set('action', 'search_biz');
124
+ url.searchParams.set('begin', '0');
125
+ url.searchParams.set('count', '1');
126
+ url.searchParams.set('query', '腾讯');
127
+ url.searchParams.set('token', token);
128
+ url.searchParams.set('lang', 'zh_CN');
129
+ url.searchParams.set('f', 'json');
130
+ url.searchParams.set('ajax', '1');
131
+
132
+ let apiOk = false;
133
+ try {
134
+ const response = await fetch(url.toString(), {
135
+ credentials: 'include',
136
+ headers: {
137
+ 'Accept': 'application/json, text/javascript, */*; q=0.01',
138
+ 'X-Requested-With': 'XMLHttpRequest'
139
+ }
140
+ });
141
+ const payload = await response.json();
142
+ apiOk = response.ok && Number(payload?.base_resp?.ret ?? 0) === 0 && Array.isArray(payload?.list);
143
+ } catch {
144
+ apiOk = false;
145
+ }
146
+
147
+ return {
148
+ href,
149
+ hasToken: Boolean(token),
150
+ loginTimedOut: false,
151
+ apiOk
152
+ };
153
+ })()`,
154
+ returnByValue: true,
155
+ awaitPromise: true,
156
+ }, 5000);
157
+ const value = result?.result?.value ?? {};
158
+ return Boolean(value.hasToken) && !value.loginTimedOut && Boolean(value.apiOk);
159
+ },
107
160
  },
108
161
  };
109
162
 
@@ -400,7 +453,12 @@ export class BrowserLoginSession {
400
453
 
401
454
  async isLoggedIn(baseline) {
402
455
  const result = await this.send('Network.getAllCookies', {});
403
- return this._config.isLoggedIn(result.cookies ?? [], baseline);
456
+ const cookieLoggedIn = this._config.isLoggedIn(result.cookies ?? [], baseline);
457
+ if (!cookieLoggedIn) return false;
458
+ if (typeof this._config.isPageLoggedIn === 'function') {
459
+ return this._config.isPageLoggedIn(this);
460
+ }
461
+ return true;
404
462
  }
405
463
 
406
464
  _startPolling(connection, baselineSession) {