yiyan-browser-agent 1.3.2 → 1.3.4

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/README.md CHANGED
@@ -1,145 +1,210 @@
1
- # doubao-browser-agent
1
+ # yiyan-browser-agent
2
2
 
3
- NPM package for interacting with Doubao (豆包) web version via Playwright.
3
+ NPM package for interacting with Yiyan (文心一言) web version via Playwright. No API key required.
4
4
 
5
5
  ## Features
6
6
 
7
- - Automated browser interaction with Doubao web version
8
- - Automatic Chrome profile management for login persistence
9
- - Retry mechanism for network failures
10
- - CLI and Node.js API support
11
- - TypeScript support with full type definitions
7
+ - 🤖 Automated browser interaction with Yiyan web version
8
+ - 🔐 Login persistence via Playwright session
9
+ - 🌍 Cross-platform: Windows / Ubuntu / macOS
10
+ - 📦 Auto-download Chromium (~150MB)
11
+ - 🛠️ CLI and Node.js API support
12
+ - 📝 TypeScript support with full type definitions
12
13
 
13
- ## Prerequisites
14
+ ## Installation
14
15
 
15
- 1. **Chrome browser** installed on your system
16
- 2. **Logged into Doubao** (https://www.doubao.com/chat/) in your Chrome browser at least once
16
+ ```bash
17
+ npm install yiyan-browser-agent
18
+ ```
17
19
 
18
- The package uses your Chrome profile to maintain login state, so you need to login manually first.
20
+ Chromium will be automatically downloaded after installation.
19
21
 
20
- ## Installation
22
+ ### Ubuntu Additional Step
21
23
 
22
24
  ```bash
23
- npm install doubao-browser-agent
25
+ npx playwright install-deps chromium
24
26
  ```
25
27
 
26
- ## Node.js API Usage
28
+ This installs required system libraries for Chromium on Ubuntu.
29
+
30
+ ## Quick Start
31
+
32
+ ### CLI Usage
33
+
34
+ ```bash
35
+ # First time: login to Yiyan
36
+ yiyan-browser-agent login
37
+
38
+ # Ask a question (headless mode)
39
+ yiyan-browser-agent ask "济宁天气情况"
40
+
41
+ # With verbose output
42
+ yiyan-browser-agent ask "什么是 TypeScript?" --verbose
43
+
44
+ # Headful mode (visible browser window)
45
+ yiyan-browser-agent ask "解释 Promise" --headful
46
+
47
+ # Check login status
48
+ yiyan-browser-agent status
49
+
50
+ # Clear saved session
51
+ yiyan-browser-agent reset
52
+ ```
53
+
54
+ ### Node.js API
27
55
 
28
56
  ```typescript
29
- import { DoubaoAgent } from 'doubao-browser-agent';
57
+ import { YiyanAgent } from 'yiyan-browser-agent';
30
58
 
31
59
  // Create agent instance
32
- const agent = new DoubaoAgent({
60
+ const agent = new YiyanAgent({
33
61
  timeout: 120000, // Timeout in milliseconds (default: 120000)
34
- retryCount: 3, // Retry count (default: 3)
35
62
  });
36
63
 
37
- // Send a question and get answer
38
- try {
39
- const answer = await agent.ask('What is TypeScript?');
40
- console.log('Answer:', answer);
41
- } catch (error) {
42
- console.error('Error:', error.message);
43
- }
64
+ // Login first time
65
+ await agent.login();
66
+
67
+ // Ask a question
68
+ const answer = await agent.ask('What is TypeScript?');
69
+ console.log('Answer:', answer);
70
+
71
+ // Headful mode (visible browser)
72
+ const answer2 = await agent.ask('Explain Promise', true);
44
73
 
45
74
  // Check login status
46
75
  const status = agent.status();
47
76
  console.log('Logged in:', status.loggedIn);
48
- console.log('Profile path:', status.profilePath);
77
+ console.log('Session path:', status.sessionPath);
49
78
 
50
- // Clear saved profile (if needed)
79
+ // Clear saved session
51
80
  await agent.reset();
52
81
  ```
53
82
 
54
- ## CLI Usage
55
-
56
- ```bash
57
- # Send a question
58
- doubao-agent ask "What is TypeScript?"
59
-
60
- # With options
61
- doubao-agent ask "Explain Promise" --timeout 60000 --retry 5
83
+ ## CLI Commands
62
84
 
63
- # Check login status
64
- doubao-agent status
85
+ | Command | Description |
86
+ |---------|-------------|
87
+ | `login` | Open browser for manual login (required first time) |
88
+ | `ask "question"` | Send question and get answer |
89
+ | `status` | Check login status |
90
+ | `reset` | Clear saved session |
65
91
 
66
- # Clear saved profile
67
- doubao-agent reset
92
+ ## CLI Options
68
93
 
69
- # Show help
70
- doubao-agent --help
71
- ```
94
+ | Option | Description |
95
+ |--------|-------------|
96
+ | `--timeout <ms>` | Timeout in milliseconds (default: 120000) |
97
+ | `--headful` | Show browser window (for debugging/captcha) |
98
+ | `--verbose` | Show detailed logs |
99
+ | `--help` | Show help message |
72
100
 
73
101
  ## API Documentation
74
102
 
75
- ### `DoubaoAgent`
103
+ ### `YiyanAgent`
76
104
 
77
- Main class for interacting with Doubao.
105
+ Main class for interacting with Yiyan.
78
106
 
79
107
  #### Constructor
80
108
 
81
109
  ```typescript
82
- new DoubaoAgent(options?: DoubaoAgentOptions)
110
+ new YiyanAgent(options?: YiyanAgentOptions)
83
111
  ```
84
112
 
85
113
  **Options:**
86
114
  - `timeout?: number` - Timeout in milliseconds (default: 120000)
87
- - `retryCount?: number` - Number of retry attempts (default: 3)
88
- - `profileDir?: string` - Custom directory for storing Chrome profile copy
89
- - `chromePath?: string` - Custom Chrome executable path
115
+ - `profileDir?: string` - Custom session directory
116
+ - `verbose?: boolean` - Enable verbose logging (default: false)
90
117
 
91
118
  #### Methods
92
119
 
93
- ##### `ask(question: string): Promise<string>`
120
+ ##### `login(): Promise<void>`
121
+
122
+ Open browser window for manual login. Login state is saved automatically.
123
+
124
+ ##### `ask(question: string, headful?: boolean): Promise<string>`
94
125
 
95
- Send a question to Doubao and return the answer.
126
+ Send question and return answer.
127
+ - `headful: false` (default) - Headless mode
128
+ - `headful: true` - Visible browser window
96
129
 
97
- ##### `status(): { loggedIn: boolean; profilePath: string }`
130
+ ##### `status(): { loggedIn: boolean; sessionPath: string }`
98
131
 
99
- Check the login status (whether profile exists).
132
+ Check login status.
100
133
 
101
134
  ##### `reset(): Promise<void>`
102
135
 
103
- Clear the saved profile copy.
136
+ Clear saved session.
104
137
 
105
138
  ### Error Types
106
139
 
107
- The package throws `DoubaoAgentError` with the following error types:
108
-
109
140
  | Type | Description |
110
141
  |------|-------------|
111
- | `BROWSER_LAUNCH` | Failed to launch Chrome browser |
112
- | `PROFILE_COPY` | Failed to copy Chrome profile |
142
+ | `BROWSER_LAUNCH` | Failed to launch Chromium |
113
143
  | `TIMEOUT` | Timeout while waiting for response |
114
144
  | `NETWORK` | Network or connection error |
115
-
116
- ```typescript
117
- import { DoubaoAgentError } from 'doubao-browser-agent';
118
-
119
- try {
120
- const answer = await agent.ask('Hello');
121
- } catch (error) {
122
- if (error instanceof DoubaoAgentError) {
123
- console.log('Error type:', error.type);
124
- console.log('Error message:', error.message);
125
- }
126
- }
127
- ```
145
+ | `CAPTCHA` | Captcha detected (use --headful) |
128
146
 
129
147
  ## How It Works
130
148
 
131
- 1. On first run, the package copies your Chrome profile to a temporary directory
132
- 2. Launches Chrome in headless mode with the copied profile
133
- 3. Navigates to Doubao chat page
134
- 4. Sends your question and waits for response
135
- 5. Extracts the response and closes the browser
149
+ 1. Uses Playwright's built-in Chromium (auto-download)
150
+ 2. Launches browser with persistent session context
151
+ 3. Navigates to Yiyan chat page
152
+ 4. Sends question and waits for response
153
+ 5. Extracts response using multiple strategies
154
+ 6. Closes browser (session saved for next use)
155
+
156
+ ## Session Storage
157
+
158
+ Session data is stored in:
159
+ - Windows: `C:\Users\<user>\.yiyan-browser-agent\session`
160
+ - Linux/macOS: `~/.yiyan-browser-agent/session`
136
161
 
137
162
  ## Supported Platforms
138
163
 
139
- - Windows (Chrome paths: `C:/Program Files/Google/Chrome/Application/chrome.exe`)
140
- - macOS (Chrome paths: `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`)
141
- - Linux (Chrome paths: `/usr/bin/google-chrome`, `/usr/bin/chrome`)
164
+ | Platform | Status | Notes |
165
+ |----------|--------|-------|
166
+ | Windows | | Direct use |
167
+ | Ubuntu | ✅ | Run `npx playwright install-deps chromium` first |
168
+ | macOS | ✅ | Direct use |
169
+
170
+ ## Troubleshooting
171
+
172
+ ### Ubuntu: Browser doesn't start
173
+
174
+ ```bash
175
+ npx playwright install chromium
176
+ npx playwright install-deps chromium
177
+ yiyan-browser-agent login --verbose
178
+ ```
179
+
180
+ ### Timeout in headless mode
181
+
182
+ ```bash
183
+ # Use headful mode to see what's happening
184
+ yiyan-browser-agent ask "question" --headful --verbose
185
+ ```
186
+
187
+ ### Captcha detected
188
+
189
+ ```bash
190
+ # Use headful mode to manually solve captcha
191
+ yiyan-browser-agent ask "question" --headful
192
+ ```
193
+
194
+ ## Comparison with deepseek-browser-agent
195
+
196
+ This package follows similar architecture to [deepseek-browser-agent](https://github.com/Omar-Azam/deepseek-browser-agent):
197
+
198
+ | Feature | yiyan-browser-agent | deepseek-browser-agent |
199
+ |---------|---------------------|------------------------|
200
+ | Browser | Playwright Chromium | Playwright Chromium |
201
+ | Login | Persistent session | Persistent session |
202
+ | Platform | Win/Ubuntu/macOS | Linux |
142
203
 
143
204
  ## License
144
205
 
145
- MIT
206
+ MIT
207
+
208
+ ## Repository
209
+
210
+ https://github.com/picha/yiyan-browser-agent
package/dist/cli.js CHANGED
@@ -7,8 +7,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
7
7
  });
8
8
 
9
9
  // src/agent.ts
10
- import path2 from "path";
11
- import os2 from "os";
10
+ import path from "path";
11
+ import os from "os";
12
12
 
13
13
  // src/types.ts
14
14
  var YiyanAgentError = class extends Error {
@@ -29,8 +29,6 @@ var YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
29
29
 
30
30
  // src/browser.ts
31
31
  import { chromium } from "playwright";
32
- import path from "path";
33
- import os from "os";
34
32
  import fs from "fs";
35
33
  function log(verbose, msg) {
36
34
  if (verbose) {
@@ -180,20 +178,7 @@ async function waitForUserAction(page, reason, verbose = false) {
180
178
  }
181
179
  log(verbose, "\u26A0 \u7B49\u5F85\u7528\u6237\u64CD\u4F5C\u8D85\u65F6\uFF083\u5206\u949F\uFF09");
182
180
  }
183
- async function saveDebugScreenshot(page, name, verbose) {
184
- try {
185
- const debugDir = path.join(os.homedir(), ".yiyan-browser-agent", "debug");
186
- if (!fs.existsSync(debugDir)) {
187
- fs.mkdirSync(debugDir, { recursive: true });
188
- }
189
- const screenshotPath = path.join(debugDir, `${name}-${Date.now()}.png`);
190
- await page.screenshot({ path: screenshotPath, fullPage: true });
191
- log(verbose, `\u8C03\u8BD5\u622A\u56FE\u5DF2\u4FDD\u5B58: ${screenshotPath}`);
192
- } catch {
193
- }
194
- }
195
181
  async function sendMessage(page, message, verbose = false, headful = false) {
196
- await saveDebugScreenshot(page, "before-send", verbose);
197
182
  const inputSelectors = [
198
183
  '[contenteditable="true"][role="textbox"]',
199
184
  '[contenteditable="true"]',
@@ -213,18 +198,15 @@ async function sendMessage(page, message, verbose = false, headful = false) {
213
198
  }
214
199
  }
215
200
  if (!inputElement) {
216
- await saveDebugScreenshot(page, "no-input-found", verbose);
217
201
  throw new YiyanAgentError("NETWORK", "Cannot find the Yiyan chat input box");
218
202
  }
219
203
  log(verbose, "\u70B9\u51FB\u8F93\u5165\u6846\u83B7\u53D6\u7126\u70B9...");
220
204
  await inputElement.click({ force: true });
221
205
  await page.waitForTimeout(500);
222
- await saveDebugScreenshot(page, "after-click", verbose);
223
206
  log(verbose, `\u8F93\u5165\u95EE\u9898: "${message}"`);
224
207
  await inputElement.fill(message);
225
208
  await page.waitForTimeout(500);
226
209
  const filledValue = await inputElement.innerText();
227
- log(verbose, `\u8F93\u5165\u6846\u5185\u5BB9: "${filledValue.substring(0, 50)}"`);
228
210
  if (!filledValue.includes(message)) {
229
211
  log(verbose, "fill \u5931\u8D25\uFF0C\u5C1D\u8BD5 keyboard.type...");
230
212
  await inputElement.click({ force: true });
@@ -232,11 +214,9 @@ async function sendMessage(page, message, verbose = false, headful = false) {
232
214
  await page.keyboard.type(message, { delay: 50 });
233
215
  await page.waitForTimeout(500);
234
216
  }
235
- await saveDebugScreenshot(page, "after-input", verbose);
236
217
  log(verbose, "\u6309 Enter \u53D1\u9001\u6D88\u606F...");
237
218
  await page.keyboard.press("Enter");
238
219
  await page.waitForTimeout(3e3);
239
- await saveDebugScreenshot(page, "after-send", verbose);
240
220
  if (await checkCaptcha(page, verbose)) {
241
221
  if (headful) {
242
222
  await waitForUserAction(page, "captcha", verbose);
@@ -428,7 +408,7 @@ async function extractReply(page, question, verbose = false) {
428
408
  }
429
409
 
430
410
  // src/agent.ts
431
- var DEFAULT_SESSION_DIR = path2.join(os2.homedir(), ".yiyan-browser-agent", "session");
411
+ var DEFAULT_SESSION_DIR = path.join(os.homedir(), ".yiyan-browser-agent", "session");
432
412
  var YiyanAgent = class {
433
413
  options;
434
414
  sessionDir;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/agent.ts","../src/types.ts","../src/browser.ts","../src/cli.ts"],"sourcesContent":["// src/agent.ts\nimport path from 'path';\nimport os from 'os';\nimport {\n YiyanAgentOptions,\n DEFAULT_OPTIONS,\n YiyanAgentError,\n} from './types';\nimport {\n launchBrowser,\n closeBrowser,\n navigateToYiyan,\n sendMessage,\n waitForReply,\n extractReply,\n checkLoggedIn,\n waitForUserAction,\n} from './browser';\n\n/** 默认 session 存储目录 */\nconst DEFAULT_SESSION_DIR = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\n\n/**\n * 文心一言浏览器代理\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport class YiyanAgent {\n private options: Required<YiyanAgentOptions>;\n private sessionDir: string;\n private verbose: boolean;\n\n constructor(options?: YiyanAgentOptions & { verbose?: boolean }) {\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n this.sessionDir = this.options.profileDir || DEFAULT_SESSION_DIR;\n\n this.verbose = options?.verbose ?? false;\n }\n\n /**\n * 发送问题并获取答案\n * @param question 问题文本\n * @param headful 是否使用有头浏览器(可见窗口),默认为 false(headless)\n */\n async ask(question: string, headful = false): Promise<string> {\n return this.executeAsk(question, headful);\n }\n\n /**\n * 执行单次问答\n */\n private async executeAsk(question: string, headful: boolean): Promise<string> {\n // 启动浏览器(使用 Playwright 内置 Chromium)\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: !headful,\n timeout: this.options.timeout,\n verbose: this.verbose,\n });\n\n try {\n // 导航到文心一言\n await navigateToYiyan(page, this.verbose);\n\n // 检查登录状态\n const isLoggedIn = await checkLoggedIn(page, this.verbose);\n\n if (!isLoggedIn) {\n if (headful) {\n await waitForUserAction(page, 'login', this.verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Not logged in. Please run \"yiyan-agent login\" first, or use headed mode.'\n );\n }\n }\n\n // 发送消息\n await sendMessage(page, question, this.verbose, headful);\n\n // 等待回复\n await waitForReply(page, this.options.timeout, this.verbose, headful);\n\n // 提取回复\n const reply = await extractReply(page, question, this.verbose);\n\n return reply;\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 登录文心一言(打开有头浏览器让用户手动登录)\n * 登录成功后,后续的 ask 调用将自动使用登录状态\n */\n async login(): Promise<void> {\n // 启动有头浏览器\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: 60000,\n verbose: this.verbose,\n });\n\n try {\n await navigateToYiyan(page, this.verbose);\n\n // 输出提示信息\n process.stderr.write('\\n[yiyan-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-agent] ║ ║\\n');\n process.stderr.write('[yiyan-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-agent] ✓ Login complete, saving session...\\n');\n\n // 等待一下确保登录状态保存到 session\n await new Promise(resolve => setTimeout(resolve, 3000));\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 等待用户按 Enter\n */\n private async waitForEnter(): Promise<void> {\n const readline = await import('readline');\n return new Promise<void>((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n rl.question('Press ENTER to continue...', () => {\n rl.close();\n resolve();\n });\n });\n }\n\n /**\n * 清除保存的 session\n */\n async reset(): Promise<void> {\n const fs = await import('fs/promises');\n try {\n await fs.rm(this.sessionDir, { recursive: true, force: true });\n } catch {\n // 目录不存在,忽略\n }\n }\n\n /**\n * 检查状态\n */\n status(): { loggedIn: boolean; sessionPath: string } {\n const fs = require('fs');\n return {\n loggedIn: fs.existsSync(this.sessionDir),\n sessionPath: this.sessionDir,\n };\n }\n}","/**\n * yiyan-browser-agent 类型定义\n */\n\n/** 配置选项 */\nexport interface YiyanAgentOptions {\n /** 超时毫秒,默认 120000 */\n timeout?: number;\n /** 重试次数,默认 3 */\n retryCount?: number;\n /** 自定义 profile 目录 */\n profileDir?: string;\n /** 自定义 Chrome 可执行文件路径 */\n chromePath?: string;\n}\n\n/** CLI 输出格式 */\nexport interface CliOutput {\n success: boolean;\n /** 用户发送的问题 */\n question: string;\n /** 成功时有值 */\n answer?: string;\n /** 失败时有值 */\n error?: string;\n /** 耗时毫秒 */\n duration: number;\n}\n\n/** 错误类型 */\nexport type YiyanAgentErrorType =\n | 'BROWSER_LAUNCH'\n | 'PROFILE_COPY'\n | 'TIMEOUT'\n | 'NETWORK'\n | 'CAPTCHA';\n\n/** 自定义错误类 */\nexport class YiyanAgentError extends Error {\n constructor(\n public type: YiyanAgentErrorType,\n message: string\n ) {\n super(message);\n this.name = 'YiyanAgentError';\n }\n}\n\n/** 默认配置 */\nexport const DEFAULT_OPTIONS: Required<YiyanAgentOptions> = {\n timeout: 120000,\n retryCount: 3,\n profileDir: '',\n chromePath: '',\n};\n\n/** 文心一言网页 URL */\nexport const YIYAN_CHAT_URL = 'https://yiyan.baidu.com/';\n","// src/browser.ts — Playwright controller for Yiyan (文心一言)\nimport { chromium, Page, BrowserContext } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n/** 日志输出(仅 verbose 模式) */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-agent] ${msg}\\n`);\n }\n}\n\n/**\n * 启动浏览器(使用 Playwright 内置 Chromium)\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport async function launchBrowser(\n options: {\n sessionDir: string;\n headless: boolean;\n timeout?: number;\n verbose?: boolean;\n }\n): Promise<{ context: BrowserContext; page: Page }> {\n const { sessionDir, headless, timeout = 30000, verbose = false } = options;\n\n try {\n log(verbose, '启动 Chromium 浏览器...');\n\n // 确保 session 目录存在\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\n // 使用 launchPersistentContext,类似 deepseek-browser-agent\n const context = await chromium.launchPersistentContext(sessionDir, {\n headless,\n viewport: { width: 1280, height: 900 },\n userAgent: [\n 'Mozilla/5.0 (X11; Linux x86_64)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/124.0.0.0 Safari/537.36',\n ].join(' '),\n args: [\n '--disable-blink-features=AutomationControlled',\n '--no-first-run',\n '--no-default-browser-check',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n });\n\n // 设置超时\n context.setDefaultTimeout(timeout);\n\n // 获取或创建页面\n const pages = context.pages();\n const page = pages.length > 0 ? pages[0] : await context.newPage();\n\n // 隐藏自动化信号\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', { get: () => false });\n });\n\n log(verbose, '浏览器启动完成');\n return { context, page };\n } catch (error) {\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 关闭浏览器\n */\nexport async function closeBrowser(\n context: BrowserContext,\n verbose?: boolean\n): Promise<void> {\n log(!!verbose, '关闭浏览器...');\n try {\n await context.close();\n log(!!verbose, '浏览器已关闭');\n } catch {\n // 忽略关闭错误\n }\n}\n\n/**\n * 导航到文心一言聊天页面\n */\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n log(verbose, '导航到文心一言聊天页面...');\n try {\n await page.goto(YIYAN_CHAT_URL, {\n waitUntil: 'domcontentloaded',\n timeout: 30000,\n });\n await page.waitForTimeout(1500);\n log(verbose, '页面加载完成');\n } catch (err) {\n log(verbose, `导航警告: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * 检测文心一言验证码弹窗\n */\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const captchaIndicators = [\n '请完成下列验证后继续',\n '按住左边按钮拖动',\n '滑动验证',\n '点击验证',\n '安全验证',\n 'captcha',\n '请完成验证',\n ];\n\n const hasCaptcha = await page.evaluate((indicators) => {\n const bodyText = document.body.innerText || '';\n for (const indicator of indicators) {\n if (bodyText.includes(indicator)) return true;\n }\n // 检查是否有弹窗/遮罩层\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n if (dialogs.length > 0) return true;\n return false;\n }, captchaIndicators);\n\n if (hasCaptcha) {\n log(verbose, '⚠ 检测到验证码弹窗!');\n }\n return hasCaptcha;\n}\n\n/**\n * 检测是否已登录文心一言\n */\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n const isLoggedIn = await page.evaluate(() => {\n // 文心一言未登录时:页面有\"登录\"按钮和\"未登录\"文字\n const bodyText = document.body.innerText || '';\n\n // 如果有\"未登录\"文字 = 未登录\n if (bodyText.includes('未登录')) return false;\n\n // 检查是否有\"登录\"按钮\n const loginButtons = document.querySelectorAll('button');\n for (const btn of loginButtons) {\n const text = btn.textContent?.trim() || '';\n if (text === '登录') {\n return false; // 有登录按钮 = 未登录\n }\n }\n\n // 如果没有\"登录\"按钮和\"未登录\"文字,说明已登录\n return true;\n });\n\n if (isLoggedIn) {\n log(verbose, '✓ 已检测到登录状态');\n } else {\n log(verbose, '⚠ 未检测到登录状态');\n }\n return isLoggedIn;\n}\n\n/**\n * 有头模式下,暂停等待用户手动操作(过验证码/登录)\n */\nexport async function waitForUserAction(\n page: Page,\n reason: 'captcha' | 'login' | 'no-reply',\n verbose = false\n): Promise<void> {\n const reasonText = reason === 'captcha'\n ? '检测到验证码,请在浏览器中手动完成验证'\n : reason === 'login'\n ? '检测到未登录,请在浏览器中手动登录'\n : 'AI 未回复,请检查浏览器是否需要手动操作(验证码/登录)';\n\n process.stderr.write(`\\n[yiyan-agent] ⚠ ${reasonText}\\n`);\n process.stderr.write('[yiyan-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n // 轮询检测问题是否已解决\n const maxWait = 180000; // 最多等 3 分钟\n const startTime = Date.now();\n\n while (Date.now() - startTime < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha') {\n const stillHasCaptcha = await checkCaptcha(page, false);\n if (!stillHasCaptcha) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n } else if (reason === 'login') {\n const loggedIn = await checkLoggedIn(page, false);\n if (loggedIn) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n } else {\n // no-reply:检测 AI 回复是否出现\n const hasReply = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (!answerBox) return false;\n const text = answerBox.innerText?.trim() || '';\n return text.length > 0;\n });\n if (hasReply) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n/**\n * 保存调试截图\n */\nasync function saveDebugScreenshot(page: Page, name: string, verbose: boolean): Promise<void> {\n try {\n const debugDir = path.join(os.homedir(), '.yiyan-browser-agent', 'debug');\n if (!fs.existsSync(debugDir)) {\n fs.mkdirSync(debugDir, { recursive: true });\n }\n const screenshotPath = path.join(debugDir, `${name}-${Date.now()}.png`);\n await page.screenshot({ path: screenshotPath, fullPage: true });\n log(verbose, `调试截图已保存: ${screenshotPath}`);\n } catch {\n // 截图失败不影响主流程\n }\n}\n\n/**\n * 发送消息到文心一言\n */\nexport async function sendMessage(page: Page, message: string, verbose = false, headful = false): Promise<void> {\n // 调试截图:发送前\n await saveDebugScreenshot(page, 'before-send', verbose);\n\n // 文心一言使用 contenteditable div 而不是 textarea\n const inputSelectors = [\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n 'textarea[placeholder]',\n 'textarea',\n ];\n\n log(verbose, '等待输入框出现...');\n let inputElement: any = null;\n for (const sel of inputSelectors) {\n try {\n inputElement = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (inputElement) {\n log(verbose, `✓ 输入框已找到: ${sel}`);\n break;\n }\n } catch {}\n }\n\n if (!inputElement) {\n // 调试截图:找不到输入框\n await saveDebugScreenshot(page, 'no-input-found', verbose);\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击输入框获取焦点\n log(verbose, '点击输入框获取焦点...');\n await inputElement.click({ force: true });\n await page.waitForTimeout(500);\n\n // 调试截图:点击后\n await saveDebugScreenshot(page, 'after-click', verbose);\n\n // 清除现有内容并输入 - 使用 fill 方法更可靠\n log(verbose, `输入问题: \"${message}\"`);\n await inputElement.fill(message);\n await page.waitForTimeout(500);\n\n // 验证输入是否成功\n const filledValue = await inputElement.innerText();\n log(verbose, `输入框内容: \"${filledValue.substring(0, 50)}\"`);\n if (!filledValue.includes(message)) {\n // 如果 fill 失败,尝试 keyboard.type\n log(verbose, 'fill 失败,尝试 keyboard.type...');\n await inputElement.click({ force: true });\n await page.keyboard.press('Control+a');\n await page.keyboard.type(message, { delay: 50 });\n await page.waitForTimeout(500);\n }\n\n // 调试截图:输入后\n await saveDebugScreenshot(page, 'after-input', verbose);\n\n // 按 Enter 发送\n log(verbose, '按 Enter 发送消息...');\n await page.keyboard.press('Enter');\n await page.waitForTimeout(3000);\n\n // 调试截图:发送后\n await saveDebugScreenshot(page, 'after-send', verbose);\n\n // 检查是否触发了验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha. Use --headful to manually solve it.'\n );\n }\n }\n}\n\n/**\n * 等待回复完成\n */\nexport async function waitForReply(\n page: Page,\n timeout: number,\n verbose = false,\n headful = false\n): Promise<void> {\n const maxWait = Math.min(timeout, 60000);\n log(verbose, `等待 AI 回复(最多 ${maxWait / 1000} 秒)...`);\n\n const startTime = Date.now();\n let lastLen = 0;\n let stableCount = 0;\n let replyStarted = false;\n\n while (Date.now() - startTime < maxWait) {\n const state = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (answerBox) {\n const text = answerBox.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n if (cardList) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const text = lastCard.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n }\n\n return { hasAiReply: false, aiTextLen: 0, aiPreview: '' };\n });\n\n if (state.hasAiReply && state.aiTextLen > 0) {\n if (!replyStarted) {\n log(verbose, `✓ AI 回复已开始生成(${state.aiTextLen}字)`);\n replyStarted = true;\n }\n\n // 文本长度不再变化 → 回复完成\n if (state.aiTextLen === lastLen) {\n stableCount++;\n if (stableCount >= 3) {\n log(verbose, `✓ AI 回复已完成(${state.aiTextLen}字)`);\n break;\n }\n } else {\n stableCount = 0;\n lastLen = state.aiTextLen;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n if (!replyStarted) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha.'\n );\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError(\n 'TIMEOUT',\n 'AI reply timeout in headless mode. Try running login first, or use headed mode.'\n );\n }\n }\n\n // 额外等待确保渲染完成\n await page.waitForTimeout(1000);\n}\n\n/**\n * 提取回复内容\n */\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复内容...');\n\n const reply = await page.evaluate((userQuestion: string) => {\n const debugInfo: string[] = [];\n\n // 方法1:answerBox 中排除思考过程\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n debugInfo.push(`answerBox found: ${!!answerBox}`);\n if (answerBox) {\n const clone = answerBox.cloneNode(true) as HTMLElement;\n const processItems = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"]');\n for (const item of processItems) item.remove();\n const toolMessages = clone.querySelectorAll('[class*=\"toolMessage\"]');\n for (const msg of toolMessages) msg.remove();\n const thinkHeaders = clone.querySelectorAll('[class*=\"headerMask\"], [class*=\"topHeader\"]');\n for (const h of thinkHeaders) h.remove();\n\n const text = clone.innerText?.trim() || '';\n const cleanedText = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/^准备输出结果\\s*/, '')\n .trim();\n\n if (cleanedText.length > 0) {\n debugInfo.push(`method1 success: ${cleanedText.length} chars`);\n return JSON.stringify({ text: cleanedText, debug: debugInfo });\n }\n }\n\n // 方法2:mdRenderContainer\n const allMdContainers = document.querySelectorAll('[class*=\"mdRenderContainer\"]');\n debugInfo.push(`mdRenderContainer count: ${allMdContainers.length}`);\n for (const container of allMdContainers) {\n const parent = container.parentElement;\n const parentClass = parent?.className?.toString() || '';\n if (parentClass.includes('toolMessage') || parentClass.includes('process')) continue;\n const text = container.innerText?.trim() || '';\n if (text.length > 10) {\n debugInfo.push(`method2 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n\n // 方法3:dialogueCardList\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n debugInfo.push(`dialogueCardList found: ${!!cardList}`);\n if (cardList && cardList.children.length > 0) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const clone = lastCard.cloneNode(true) as HTMLElement;\n const thinkEls = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"], [class*=\"toolMessage\"]');\n for (const el of thinkEls) el.remove();\n const text = clone.innerText?.trim() || '';\n if (text.length > 0) {\n debugInfo.push(`method3 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n }\n\n // 方法4:页面文本解析\n const fullText = document.body.innerText;\n const lines = fullText.split('\\n').map(l => l.trim()).filter(l => l.length > 0);\n const uiWords = new Set([\n '文心一言', '新对话', '创意写作', '智慧绘图', '超级智能体', '更多',\n '我的收藏', '项目', '对话', '暂无记录', '未登录', '登录',\n '内容由AI生成,仅供参考,请仔细甄别', '参考',\n ]);\n const thinkingKeywords = [\n '深度思考已完成', '思考完成', '准备输出结果',\n ];\n\n const userQIdx = lines.findIndex(l => l === userQuestion || l.includes(userQuestion));\n debugInfo.push(`userQ idx: ${userQIdx}, lines: ${lines.length}`);\n\n if (userQIdx >= 0) {\n const replyLines: string[] = [];\n for (let i = userQIdx + 1; i < lines.length; i++) {\n const line = lines[i];\n if (uiWords.has(line)) continue;\n if (thinkingKeywords.some(kw => line.includes(kw))) continue;\n if (line.startsWith('搜索') || line.includes('篇资料')) continue;\n if (line.match(/^参考\\d+个网页/)) continue;\n if (line.length > 0) replyLines.push(line);\n if (line === '快速' || line === '更多' || line.includes('内容由AI生成')) break;\n }\n if (replyLines.length > 0) {\n debugInfo.push(`method4 success: ${replyLines.length} lines`);\n return JSON.stringify({ text: replyLines.join('\\n'), debug: debugInfo });\n }\n }\n\n debugInfo.push('ALL METHODS FAILED');\n return JSON.stringify({ text: '', debug: debugInfo });\n }, question);\n\n let parsed: { text: string; debug: string[] };\n try {\n parsed = JSON.parse(reply);\n } catch {\n parsed = { text: reply, debug: [] };\n }\n\n for (const line of parsed.debug) {\n log(verbose, ` [extract] ${line}`);\n }\n\n if (parsed.text && parsed.text.length > 0) {\n log(verbose, `提取成功,回复长度: ${parsed.text.length} 字符`);\n return parsed.text;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply content');\n}","/**\n * CLI 命令行工具\n */\nimport { YiyanAgent } from './agent';\nimport { CliOutput, YiyanAgentOptions } from './types';\n\n/** CLI 帮助信息 */\nexport function printHelp(): void {\n console.log(`\nyiyan-agent - 文心一言浏览器代理 CLI\n\n用法:\n yiyan-agent login 首次登录文心一言(会打开浏览器窗口)\n yiyan-agent ask \"问题\" [--timeout ms] [--headful] [--verbose]\n yiyan-agent status 检查登录状态\n yiyan-agent reset 清除保存的 session\n\n命令:\n login 打开浏览器手动登录文心一言(首次使用必须先登录)\n ask 发送问题并获取答案(默认无头模式,不弹窗;登录后直接使用)\n status 检查登录状态\n reset 清除保存的 session\n\n选项:\n --timeout <ms> 超时时间(毫秒),默认 120000\n --headful 使用有头浏览器(可见窗口,用于手动过验证码)\n --verbose 显示详细日志(调试用)\n --help 显示帮助信息\n\n示例:\n yiyan-agent login # 首次使用:登录文心一言\n yiyan-agent ask \"什么是 TypeScript?\" # 提问(静默模式)\n yiyan-agent ask \"解释 Promise\" --verbose # 显示详细日志\n yiyan-agent ask \"30+30=\" --headful # 有头模式(可手动过验证码)\n yiyan-agent status\n yiyan-agent reset\n\n流程:\n 1. 先运行 yiyan-agent login 登录(只需一次,登录状态会保存)\n 2. 之后直接 yiyan-agent ask \"问题\" 即可,无需再登录\n 3. 如果遇到验证码,加 --headful 切换有头模式手动处理\n\n提示:\n Chromium 会自动下载(约150MB),无需手动安装 Chrome\n Session 保存在 ~/.yiyan-browser-agent/session 目录\n`);\n}\n\n/** 解析后的 CLI 参数 */\ninterface ParsedArgs {\n command: 'ask' | 'status' | 'reset' | 'login' | 'help' | null;\n question?: string;\n timeout?: number;\n headful?: boolean;\n verbose?: boolean;\n}\n\n/**\n * 解析 CLI 参数\n */\nexport function parseCliArgs(args: string[]): ParsedArgs {\n const result: ParsedArgs = {\n command: null,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help') {\n result.command = 'help';\n return result;\n }\n\n if (arg === 'ask') {\n result.command = 'ask';\n if (i + 1 < args.length && !args[i + 1].startsWith('--')) {\n result.question = args[i + 1];\n i++;\n }\n }\n\n if (arg === 'status') {\n result.command = 'status';\n }\n\n if (arg === 'reset') {\n result.command = 'reset';\n }\n\n if (arg === 'login') {\n result.command = 'login';\n }\n\n if (arg === '--timeout') {\n if (i + 1 < args.length) {\n result.timeout = parseInt(args[i + 1], 10);\n i++;\n }\n }\n\n if (arg === '--headful') {\n result.headful = true;\n }\n\n if (arg === '--verbose') {\n result.verbose = true;\n }\n }\n\n return result;\n}\n\n/**\n * 格式化 CLI 输出为 JSON\n */\nexport function formatCliOutput(output: CliOutput): string {\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * CLI 主入口\n */\nexport async function runCli(args: string[]): Promise<void> {\n const parsed = parseCliArgs(args);\n\n if (parsed.command === 'help' || parsed.command === null) {\n printHelp();\n return;\n }\n\n const options: YiyanAgentOptions & { verbose?: boolean } = {};\n if (parsed.timeout) {\n options.timeout = parsed.timeout;\n }\n if (parsed.verbose) {\n options.verbose = true;\n }\n\n const agent = new YiyanAgent(options);\n\n if (parsed.command === 'login') {\n try {\n await agent.login();\n console.log(formatCliOutput({\n success: true,\n question: 'login',\n answer: 'Login successful! You can now use \"ask\" command.',\n duration: 0,\n }));\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.log(formatCliOutput({\n success: false,\n question: 'login',\n error: errorMessage,\n duration: 0,\n }));\n }\n return;\n }\n\n if (parsed.command === 'status') {\n const status = agent.status();\n console.log(formatCliOutput({\n success: true,\n question: 'status',\n answer: JSON.stringify(status),\n duration: 0,\n }));\n return;\n }\n\n if (parsed.command === 'reset') {\n await agent.reset();\n console.log(formatCliOutput({\n success: true,\n question: 'reset',\n answer: 'Session cleared successfully',\n duration: 0,\n }));\n return;\n }\n\n if (parsed.command === 'ask') {\n if (!parsed.question) {\n console.log(formatCliOutput({\n success: false,\n question: '',\n error: 'No question provided. Usage: ask \"your question\"',\n duration: 0,\n }));\n return;\n }\n\n const startTime = Date.now();\n try {\n const answer = await agent.ask(parsed.question, !!parsed.headful);\n const duration = Date.now() - startTime;\n console.log(formatCliOutput({\n success: true,\n question: parsed.question,\n answer,\n duration,\n }));\n } catch (error) {\n const duration = Date.now() - startTime;\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.log(formatCliOutput({\n success: false,\n question: parsed.question,\n error: errorMessage,\n duration,\n }));\n }\n return;\n }\n}\n\n// 如果直接运行此文件,执行 CLI\nconst scriptPath = process.argv[1]?.replace(/\\\\/g, '/');\nconst importUrl = import.meta.url.replace(/^file:\\/\\//, '');\nif (scriptPath && (importUrl === scriptPath || importUrl === '/' + scriptPath)) {\n const args = process.argv.slice(2);\n runCli(args).catch(console.error);\n}"],"mappings":"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","names":["path","os","path","os","fs"]}
1
+ {"version":3,"sources":["../src/agent.ts","../src/types.ts","../src/browser.ts","../src/cli.ts"],"sourcesContent":["// src/agent.ts\nimport path from 'path';\nimport os from 'os';\nimport {\n YiyanAgentOptions,\n DEFAULT_OPTIONS,\n YiyanAgentError,\n} from './types';\nimport {\n launchBrowser,\n closeBrowser,\n navigateToYiyan,\n sendMessage,\n waitForReply,\n extractReply,\n checkLoggedIn,\n waitForUserAction,\n} from './browser';\n\n/** 默认 session 存储目录 */\nconst DEFAULT_SESSION_DIR = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\n\n/**\n * 文心一言浏览器代理\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport class YiyanAgent {\n private options: Required<YiyanAgentOptions>;\n private sessionDir: string;\n private verbose: boolean;\n\n constructor(options?: YiyanAgentOptions & { verbose?: boolean }) {\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n this.sessionDir = this.options.profileDir || DEFAULT_SESSION_DIR;\n\n this.verbose = options?.verbose ?? false;\n }\n\n /**\n * 发送问题并获取答案\n * @param question 问题文本\n * @param headful 是否使用有头浏览器(可见窗口),默认为 false(headless)\n */\n async ask(question: string, headful = false): Promise<string> {\n return this.executeAsk(question, headful);\n }\n\n /**\n * 执行单次问答\n */\n private async executeAsk(question: string, headful: boolean): Promise<string> {\n // 启动浏览器(使用 Playwright 内置 Chromium)\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: !headful,\n timeout: this.options.timeout,\n verbose: this.verbose,\n });\n\n try {\n // 导航到文心一言\n await navigateToYiyan(page, this.verbose);\n\n // 检查登录状态\n const isLoggedIn = await checkLoggedIn(page, this.verbose);\n\n if (!isLoggedIn) {\n if (headful) {\n await waitForUserAction(page, 'login', this.verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Not logged in. Please run \"yiyan-agent login\" first, or use headed mode.'\n );\n }\n }\n\n // 发送消息\n await sendMessage(page, question, this.verbose, headful);\n\n // 等待回复\n await waitForReply(page, this.options.timeout, this.verbose, headful);\n\n // 提取回复\n const reply = await extractReply(page, question, this.verbose);\n\n return reply;\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 登录文心一言(打开有头浏览器让用户手动登录)\n * 登录成功后,后续的 ask 调用将自动使用登录状态\n */\n async login(): Promise<void> {\n // 启动有头浏览器\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: 60000,\n verbose: this.verbose,\n });\n\n try {\n await navigateToYiyan(page, this.verbose);\n\n // 输出提示信息\n process.stderr.write('\\n[yiyan-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-agent] ║ ║\\n');\n process.stderr.write('[yiyan-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-agent] ✓ Login complete, saving session...\\n');\n\n // 等待一下确保登录状态保存到 session\n await new Promise(resolve => setTimeout(resolve, 3000));\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 等待用户按 Enter\n */\n private async waitForEnter(): Promise<void> {\n const readline = await import('readline');\n return new Promise<void>((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n rl.question('Press ENTER to continue...', () => {\n rl.close();\n resolve();\n });\n });\n }\n\n /**\n * 清除保存的 session\n */\n async reset(): Promise<void> {\n const fs = await import('fs/promises');\n try {\n await fs.rm(this.sessionDir, { recursive: true, force: true });\n } catch {\n // 目录不存在,忽略\n }\n }\n\n /**\n * 检查状态\n */\n status(): { loggedIn: boolean; sessionPath: string } {\n const fs = require('fs');\n return {\n loggedIn: fs.existsSync(this.sessionDir),\n sessionPath: this.sessionDir,\n };\n }\n}","/**\n * yiyan-browser-agent 类型定义\n */\n\n/** 配置选项 */\nexport interface YiyanAgentOptions {\n /** 超时毫秒,默认 120000 */\n timeout?: number;\n /** 重试次数,默认 3 */\n retryCount?: number;\n /** 自定义 profile 目录 */\n profileDir?: string;\n /** 自定义 Chrome 可执行文件路径 */\n chromePath?: string;\n}\n\n/** CLI 输出格式 */\nexport interface CliOutput {\n success: boolean;\n /** 用户发送的问题 */\n question: string;\n /** 成功时有值 */\n answer?: string;\n /** 失败时有值 */\n error?: string;\n /** 耗时毫秒 */\n duration: number;\n}\n\n/** 错误类型 */\nexport type YiyanAgentErrorType =\n | 'BROWSER_LAUNCH'\n | 'PROFILE_COPY'\n | 'TIMEOUT'\n | 'NETWORK'\n | 'CAPTCHA';\n\n/** 自定义错误类 */\nexport class YiyanAgentError extends Error {\n constructor(\n public type: YiyanAgentErrorType,\n message: string\n ) {\n super(message);\n this.name = 'YiyanAgentError';\n }\n}\n\n/** 默认配置 */\nexport const DEFAULT_OPTIONS: Required<YiyanAgentOptions> = {\n timeout: 120000,\n retryCount: 3,\n profileDir: '',\n chromePath: '',\n};\n\n/** 文心一言网页 URL */\nexport const YIYAN_CHAT_URL = 'https://yiyan.baidu.com/';\n","// src/browser.ts — Playwright controller for Yiyan (文心一言)\nimport { chromium, Page, BrowserContext } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n/** 日志输出(仅 verbose 模式) */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-agent] ${msg}\\n`);\n }\n}\n\n/**\n * 启动浏览器(使用 Playwright 内置 Chromium)\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport async function launchBrowser(\n options: {\n sessionDir: string;\n headless: boolean;\n timeout?: number;\n verbose?: boolean;\n }\n): Promise<{ context: BrowserContext; page: Page }> {\n const { sessionDir, headless, timeout = 30000, verbose = false } = options;\n\n try {\n log(verbose, '启动 Chromium 浏览器...');\n\n // 确保 session 目录存在\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\n // 使用 launchPersistentContext,类似 deepseek-browser-agent\n const context = await chromium.launchPersistentContext(sessionDir, {\n headless,\n viewport: { width: 1280, height: 900 },\n userAgent: [\n 'Mozilla/5.0 (X11; Linux x86_64)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/124.0.0.0 Safari/537.36',\n ].join(' '),\n args: [\n '--disable-blink-features=AutomationControlled',\n '--no-first-run',\n '--no-default-browser-check',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n });\n\n // 设置超时\n context.setDefaultTimeout(timeout);\n\n // 获取或创建页面\n const pages = context.pages();\n const page = pages.length > 0 ? pages[0] : await context.newPage();\n\n // 隐藏自动化信号\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', { get: () => false });\n });\n\n log(verbose, '浏览器启动完成');\n return { context, page };\n } catch (error) {\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 关闭浏览器\n */\nexport async function closeBrowser(\n context: BrowserContext,\n verbose?: boolean\n): Promise<void> {\n log(!!verbose, '关闭浏览器...');\n try {\n await context.close();\n log(!!verbose, '浏览器已关闭');\n } catch {\n // 忽略关闭错误\n }\n}\n\n/**\n * 导航到文心一言聊天页面\n */\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n log(verbose, '导航到文心一言聊天页面...');\n try {\n await page.goto(YIYAN_CHAT_URL, {\n waitUntil: 'domcontentloaded',\n timeout: 30000,\n });\n await page.waitForTimeout(1500);\n log(verbose, '页面加载完成');\n } catch (err) {\n log(verbose, `导航警告: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * 检测文心一言验证码弹窗\n */\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const captchaIndicators = [\n '请完成下列验证后继续',\n '按住左边按钮拖动',\n '滑动验证',\n '点击验证',\n '安全验证',\n 'captcha',\n '请完成验证',\n ];\n\n const hasCaptcha = await page.evaluate((indicators) => {\n const bodyText = document.body.innerText || '';\n for (const indicator of indicators) {\n if (bodyText.includes(indicator)) return true;\n }\n // 检查是否有弹窗/遮罩层\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n if (dialogs.length > 0) return true;\n return false;\n }, captchaIndicators);\n\n if (hasCaptcha) {\n log(verbose, '⚠ 检测到验证码弹窗!');\n }\n return hasCaptcha;\n}\n\n/**\n * 检测是否已登录文心一言\n */\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n const isLoggedIn = await page.evaluate(() => {\n // 文心一言未登录时:页面有\"登录\"按钮和\"未登录\"文字\n const bodyText = document.body.innerText || '';\n\n // 如果有\"未登录\"文字 = 未登录\n if (bodyText.includes('未登录')) return false;\n\n // 检查是否有\"登录\"按钮\n const loginButtons = document.querySelectorAll('button');\n for (const btn of loginButtons) {\n const text = btn.textContent?.trim() || '';\n if (text === '登录') {\n return false; // 有登录按钮 = 未登录\n }\n }\n\n // 如果没有\"登录\"按钮和\"未登录\"文字,说明已登录\n return true;\n });\n\n if (isLoggedIn) {\n log(verbose, '✓ 已检测到登录状态');\n } else {\n log(verbose, '⚠ 未检测到登录状态');\n }\n return isLoggedIn;\n}\n\n/**\n * 有头模式下,暂停等待用户手动操作(过验证码/登录)\n */\nexport async function waitForUserAction(\n page: Page,\n reason: 'captcha' | 'login' | 'no-reply',\n verbose = false\n): Promise<void> {\n const reasonText = reason === 'captcha'\n ? '检测到验证码,请在浏览器中手动完成验证'\n : reason === 'login'\n ? '检测到未登录,请在浏览器中手动登录'\n : 'AI 未回复,请检查浏览器是否需要手动操作(验证码/登录)';\n\n process.stderr.write(`\\n[yiyan-agent] ⚠ ${reasonText}\\n`);\n process.stderr.write('[yiyan-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n // 轮询检测问题是否已解决\n const maxWait = 180000; // 最多等 3 分钟\n const startTime = Date.now();\n\n while (Date.now() - startTime < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha') {\n const stillHasCaptcha = await checkCaptcha(page, false);\n if (!stillHasCaptcha) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n } else if (reason === 'login') {\n const loggedIn = await checkLoggedIn(page, false);\n if (loggedIn) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n } else {\n // no-reply:检测 AI 回复是否出现\n const hasReply = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (!answerBox) return false;\n const text = answerBox.innerText?.trim() || '';\n return text.length > 0;\n });\n if (hasReply) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n/**\n * 发送消息到文心一言\n */\nexport async function sendMessage(page: Page, message: string, verbose = false, headful = false): Promise<void> {\n // 文心一言使用 contenteditable div 而不是 textarea\n const inputSelectors = [\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n 'textarea[placeholder]',\n 'textarea',\n ];\n\n log(verbose, '等待输入框出现...');\n let inputElement: any = null;\n for (const sel of inputSelectors) {\n try {\n inputElement = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (inputElement) {\n log(verbose, `✓ 输入框已找到: ${sel}`);\n break;\n }\n } catch {}\n }\n\n if (!inputElement) {\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击输入框获取焦点\n log(verbose, '点击输入框获取焦点...');\n await inputElement.click({ force: true });\n await page.waitForTimeout(500);\n\n // 输入内容\n log(verbose, `输入问题: \"${message}\"`);\n await inputElement.fill(message);\n await page.waitForTimeout(500);\n\n // 验证输入是否成功\n const filledValue = await inputElement.innerText();\n if (!filledValue.includes(message)) {\n // 如果 fill 失败,尝试 keyboard.type\n log(verbose, 'fill 失败,尝试 keyboard.type...');\n await inputElement.click({ force: true });\n await page.keyboard.press('Control+a');\n await page.keyboard.type(message, { delay: 50 });\n await page.waitForTimeout(500);\n }\n\n // 按 Enter 发送\n log(verbose, '按 Enter 发送消息...');\n await page.keyboard.press('Enter');\n await page.waitForTimeout(3000);\n\n // 检查是否触发了验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha. Use --headful to manually solve it.'\n );\n }\n }\n}\n\n/**\n * 等待回复完成\n */\nexport async function waitForReply(\n page: Page,\n timeout: number,\n verbose = false,\n headful = false\n): Promise<void> {\n const maxWait = Math.min(timeout, 60000);\n log(verbose, `等待 AI 回复(最多 ${maxWait / 1000} 秒)...`);\n\n const startTime = Date.now();\n let lastLen = 0;\n let stableCount = 0;\n let replyStarted = false;\n\n while (Date.now() - startTime < maxWait) {\n const state = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (answerBox) {\n const text = answerBox.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n if (cardList) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const text = lastCard.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n }\n\n return { hasAiReply: false, aiTextLen: 0, aiPreview: '' };\n });\n\n if (state.hasAiReply && state.aiTextLen > 0) {\n if (!replyStarted) {\n log(verbose, `✓ AI 回复已开始生成(${state.aiTextLen}字)`);\n replyStarted = true;\n }\n\n // 文本长度不再变化 → 回复完成\n if (state.aiTextLen === lastLen) {\n stableCount++;\n if (stableCount >= 3) {\n log(verbose, `✓ AI 回复已完成(${state.aiTextLen}字)`);\n break;\n }\n } else {\n stableCount = 0;\n lastLen = state.aiTextLen;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n if (!replyStarted) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha.'\n );\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError(\n 'TIMEOUT',\n 'AI reply timeout in headless mode. Try running login first, or use headed mode.'\n );\n }\n }\n\n // 额外等待确保渲染完成\n await page.waitForTimeout(1000);\n}\n\n/**\n * 提取回复内容\n */\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复内容...');\n\n const reply = await page.evaluate((userQuestion: string) => {\n const debugInfo: string[] = [];\n\n // 方法1:answerBox 中排除思考过程\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n debugInfo.push(`answerBox found: ${!!answerBox}`);\n if (answerBox) {\n const clone = answerBox.cloneNode(true) as HTMLElement;\n const processItems = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"]');\n for (const item of processItems) item.remove();\n const toolMessages = clone.querySelectorAll('[class*=\"toolMessage\"]');\n for (const msg of toolMessages) msg.remove();\n const thinkHeaders = clone.querySelectorAll('[class*=\"headerMask\"], [class*=\"topHeader\"]');\n for (const h of thinkHeaders) h.remove();\n\n const text = clone.innerText?.trim() || '';\n const cleanedText = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/^准备输出结果\\s*/, '')\n .trim();\n\n if (cleanedText.length > 0) {\n debugInfo.push(`method1 success: ${cleanedText.length} chars`);\n return JSON.stringify({ text: cleanedText, debug: debugInfo });\n }\n }\n\n // 方法2:mdRenderContainer\n const allMdContainers = document.querySelectorAll('[class*=\"mdRenderContainer\"]');\n debugInfo.push(`mdRenderContainer count: ${allMdContainers.length}`);\n for (const container of allMdContainers) {\n const parent = container.parentElement;\n const parentClass = parent?.className?.toString() || '';\n if (parentClass.includes('toolMessage') || parentClass.includes('process')) continue;\n const text = container.innerText?.trim() || '';\n if (text.length > 10) {\n debugInfo.push(`method2 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n\n // 方法3:dialogueCardList\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n debugInfo.push(`dialogueCardList found: ${!!cardList}`);\n if (cardList && cardList.children.length > 0) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const clone = lastCard.cloneNode(true) as HTMLElement;\n const thinkEls = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"], [class*=\"toolMessage\"]');\n for (const el of thinkEls) el.remove();\n const text = clone.innerText?.trim() || '';\n if (text.length > 0) {\n debugInfo.push(`method3 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n }\n\n // 方法4:页面文本解析\n const fullText = document.body.innerText;\n const lines = fullText.split('\\n').map(l => l.trim()).filter(l => l.length > 0);\n const uiWords = new Set([\n '文心一言', '新对话', '创意写作', '智慧绘图', '超级智能体', '更多',\n '我的收藏', '项目', '对话', '暂无记录', '未登录', '登录',\n '内容由AI生成,仅供参考,请仔细甄别', '参考',\n ]);\n const thinkingKeywords = [\n '深度思考已完成', '思考完成', '准备输出结果',\n ];\n\n const userQIdx = lines.findIndex(l => l === userQuestion || l.includes(userQuestion));\n debugInfo.push(`userQ idx: ${userQIdx}, lines: ${lines.length}`);\n\n if (userQIdx >= 0) {\n const replyLines: string[] = [];\n for (let i = userQIdx + 1; i < lines.length; i++) {\n const line = lines[i];\n if (uiWords.has(line)) continue;\n if (thinkingKeywords.some(kw => line.includes(kw))) continue;\n if (line.startsWith('搜索') || line.includes('篇资料')) continue;\n if (line.match(/^参考\\d+个网页/)) continue;\n if (line.length > 0) replyLines.push(line);\n if (line === '快速' || line === '更多' || line.includes('内容由AI生成')) break;\n }\n if (replyLines.length > 0) {\n debugInfo.push(`method4 success: ${replyLines.length} lines`);\n return JSON.stringify({ text: replyLines.join('\\n'), debug: debugInfo });\n }\n }\n\n debugInfo.push('ALL METHODS FAILED');\n return JSON.stringify({ text: '', debug: debugInfo });\n }, question);\n\n let parsed: { text: string; debug: string[] };\n try {\n parsed = JSON.parse(reply);\n } catch {\n parsed = { text: reply, debug: [] };\n }\n\n for (const line of parsed.debug) {\n log(verbose, ` [extract] ${line}`);\n }\n\n if (parsed.text && parsed.text.length > 0) {\n log(verbose, `提取成功,回复长度: ${parsed.text.length} 字符`);\n return parsed.text;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply content');\n}","/**\n * CLI 命令行工具\n */\nimport { YiyanAgent } from './agent';\nimport { CliOutput, YiyanAgentOptions } from './types';\n\n/** CLI 帮助信息 */\nexport function printHelp(): void {\n console.log(`\nyiyan-agent - 文心一言浏览器代理 CLI\n\n用法:\n yiyan-agent login 首次登录文心一言(会打开浏览器窗口)\n yiyan-agent ask \"问题\" [--timeout ms] [--headful] [--verbose]\n yiyan-agent status 检查登录状态\n yiyan-agent reset 清除保存的 session\n\n命令:\n login 打开浏览器手动登录文心一言(首次使用必须先登录)\n ask 发送问题并获取答案(默认无头模式,不弹窗;登录后直接使用)\n status 检查登录状态\n reset 清除保存的 session\n\n选项:\n --timeout <ms> 超时时间(毫秒),默认 120000\n --headful 使用有头浏览器(可见窗口,用于手动过验证码)\n --verbose 显示详细日志(调试用)\n --help 显示帮助信息\n\n示例:\n yiyan-agent login # 首次使用:登录文心一言\n yiyan-agent ask \"什么是 TypeScript?\" # 提问(静默模式)\n yiyan-agent ask \"解释 Promise\" --verbose # 显示详细日志\n yiyan-agent ask \"30+30=\" --headful # 有头模式(可手动过验证码)\n yiyan-agent status\n yiyan-agent reset\n\n流程:\n 1. 先运行 yiyan-agent login 登录(只需一次,登录状态会保存)\n 2. 之后直接 yiyan-agent ask \"问题\" 即可,无需再登录\n 3. 如果遇到验证码,加 --headful 切换有头模式手动处理\n\n提示:\n Chromium 会自动下载(约150MB),无需手动安装 Chrome\n Session 保存在 ~/.yiyan-browser-agent/session 目录\n`);\n}\n\n/** 解析后的 CLI 参数 */\ninterface ParsedArgs {\n command: 'ask' | 'status' | 'reset' | 'login' | 'help' | null;\n question?: string;\n timeout?: number;\n headful?: boolean;\n verbose?: boolean;\n}\n\n/**\n * 解析 CLI 参数\n */\nexport function parseCliArgs(args: string[]): ParsedArgs {\n const result: ParsedArgs = {\n command: null,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help') {\n result.command = 'help';\n return result;\n }\n\n if (arg === 'ask') {\n result.command = 'ask';\n if (i + 1 < args.length && !args[i + 1].startsWith('--')) {\n result.question = args[i + 1];\n i++;\n }\n }\n\n if (arg === 'status') {\n result.command = 'status';\n }\n\n if (arg === 'reset') {\n result.command = 'reset';\n }\n\n if (arg === 'login') {\n result.command = 'login';\n }\n\n if (arg === '--timeout') {\n if (i + 1 < args.length) {\n result.timeout = parseInt(args[i + 1], 10);\n i++;\n }\n }\n\n if (arg === '--headful') {\n result.headful = true;\n }\n\n if (arg === '--verbose') {\n result.verbose = true;\n }\n }\n\n return result;\n}\n\n/**\n * 格式化 CLI 输出为 JSON\n */\nexport function formatCliOutput(output: CliOutput): string {\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * CLI 主入口\n */\nexport async function runCli(args: string[]): Promise<void> {\n const parsed = parseCliArgs(args);\n\n if (parsed.command === 'help' || parsed.command === null) {\n printHelp();\n return;\n }\n\n const options: YiyanAgentOptions & { verbose?: boolean } = {};\n if (parsed.timeout) {\n options.timeout = parsed.timeout;\n }\n if (parsed.verbose) {\n options.verbose = true;\n }\n\n const agent = new YiyanAgent(options);\n\n if (parsed.command === 'login') {\n try {\n await agent.login();\n console.log(formatCliOutput({\n success: true,\n question: 'login',\n answer: 'Login successful! You can now use \"ask\" command.',\n duration: 0,\n }));\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.log(formatCliOutput({\n success: false,\n question: 'login',\n error: errorMessage,\n duration: 0,\n }));\n }\n return;\n }\n\n if (parsed.command === 'status') {\n const status = agent.status();\n console.log(formatCliOutput({\n success: true,\n question: 'status',\n answer: JSON.stringify(status),\n duration: 0,\n }));\n return;\n }\n\n if (parsed.command === 'reset') {\n await agent.reset();\n console.log(formatCliOutput({\n success: true,\n question: 'reset',\n answer: 'Session cleared successfully',\n duration: 0,\n }));\n return;\n }\n\n if (parsed.command === 'ask') {\n if (!parsed.question) {\n console.log(formatCliOutput({\n success: false,\n question: '',\n error: 'No question provided. Usage: ask \"your question\"',\n duration: 0,\n }));\n return;\n }\n\n const startTime = Date.now();\n try {\n const answer = await agent.ask(parsed.question, !!parsed.headful);\n const duration = Date.now() - startTime;\n console.log(formatCliOutput({\n success: true,\n question: parsed.question,\n answer,\n duration,\n }));\n } catch (error) {\n const duration = Date.now() - startTime;\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.log(formatCliOutput({\n success: false,\n question: parsed.question,\n error: errorMessage,\n duration,\n }));\n }\n return;\n }\n}\n\n// 如果直接运行此文件,执行 CLI\nconst scriptPath = process.argv[1]?.replace(/\\\\/g, '/');\nconst importUrl = import.meta.url.replace(/^file:\\/\\//, '');\nif (scriptPath && (importUrl === scriptPath || importUrl === '/' + scriptPath)) {\n const args = process.argv.slice(2);\n runCli(args).catch(console.error);\n}"],"mappings":";;;;;;;;;AACA,OAAO,UAAU;AACjB,OAAO,QAAQ;;;ACoCR,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACS,MACP,SACA;AACA,UAAM,OAAO;AAHN;AAIP,SAAK,OAAO;AAAA,EACd;AAAA,EALS;AAMX;AAGO,IAAM,kBAA+C;AAAA,EAC1D,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AACd;AAGO,IAAM,iBAAiB;;;ACxD9B,SAAS,gBAAsC;AAI/C,OAAO,QAAQ;AAGf,SAAS,IAAI,SAAkB,KAAmB;AAChD,MAAI,SAAS;AACX,YAAQ,OAAO,MAAM,iBAAiB,GAAG;AAAA,CAAI;AAAA,EAC/C;AACF;AAMA,eAAsB,cACpB,SAMkD;AAClD,QAAM,EAAE,YAAY,UAAU,UAAU,KAAO,UAAU,MAAM,IAAI;AAEnE,MAAI;AACF,QAAI,SAAS,6CAAoB;AAGjC,QAAI,CAAC,GAAG,WAAW,UAAU,GAAG;AAC9B,SAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,IAC9C;AAGA,UAAM,UAAU,MAAM,SAAS,wBAAwB,YAAY;AAAA,MACjE;AAAA,MACA,UAAU,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,MACrC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,MACV,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,mBAAmB,CAAC,qBAAqB;AAAA,IAC3C,CAAC;AAGD,YAAQ,kBAAkB,OAAO;AAGjC,UAAM,QAAQ,QAAQ,MAAM;AAC5B,UAAM,OAAO,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,MAAM,QAAQ,QAAQ;AAGjE,UAAM,KAAK,cAAc,MAAM;AAC7B,aAAO,eAAe,WAAW,aAAa,EAAE,KAAK,MAAM,MAAM,CAAC;AAAA,IACpE,CAAC;AAED,QAAI,SAAS,4CAAS;AACtB,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACrF;AAAA,EACF;AACF;AAKA,eAAsB,aACpB,SACA,SACe;AACf,MAAI,CAAC,CAAC,SAAS,mCAAU;AACzB,MAAI;AACF,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,CAAC,SAAS,sCAAQ;AAAA,EACzB,QAAQ;AAAA,EAER;AACF;AAKA,eAAsB,gBAAgB,MAAY,UAAU,OAAsB;AAChF,MAAI,SAAS,uEAAgB;AAC7B,MAAI;AACF,UAAM,KAAK,KAAK,gBAAgB;AAAA,MAC9B,WAAW;AAAA,MACX,SAAS;AAAA,IACX,CAAC;AACD,UAAM,KAAK,eAAe,IAAI;AAC9B,QAAI,SAAS,sCAAQ;AAAA,EACvB,SAAS,KAAK;AACZ,QAAI,SAAS,6BAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,EAC1E;AACF;AAKA,eAAsB,aAAa,MAAY,UAAU,OAAyB;AAChF,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,KAAK,SAAS,CAAC,eAAe;AACrD,UAAM,WAAW,SAAS,KAAK,aAAa;AAC5C,eAAW,aAAa,YAAY;AAClC,UAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AAAA,IAC3C;AAEA,UAAM,UAAU,SAAS,iBAAiB,wDAAwD;AAClG,QAAI,QAAQ,SAAS,EAAG,QAAO;AAC/B,WAAO;AAAA,EACT,GAAG,iBAAiB;AAEpB,MAAI,YAAY;AACd,QAAI,SAAS,+DAAa;AAAA,EAC5B;AACA,SAAO;AACT;AAKA,eAAsB,cAAc,MAAY,UAAU,OAAyB;AACjF,QAAM,aAAa,MAAM,KAAK,SAAS,MAAM;AAE3C,UAAM,WAAW,SAAS,KAAK,aAAa;AAG5C,QAAI,SAAS,SAAS,oBAAK,EAAG,QAAO;AAGrC,UAAM,eAAe,SAAS,iBAAiB,QAAQ;AACvD,eAAW,OAAO,cAAc;AAC9B,YAAM,OAAO,IAAI,aAAa,KAAK,KAAK;AACxC,UAAI,SAAS,gBAAM;AACjB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,WAAO;AAAA,EACT,CAAC;AAED,MAAI,YAAY;AACd,QAAI,SAAS,yDAAY;AAAA,EAC3B,OAAO;AACL,QAAI,SAAS,yDAAY;AAAA,EAC3B;AACA,SAAO;AACT;AAKA,eAAsB,kBACpB,MACA,QACA,UAAU,OACK;AACf,QAAM,aAAa,WAAW,YAC1B,uHACA,WAAW,UACX,2GACA;AAEJ,UAAQ,OAAO,MAAM;AAAA,uBAAqB,UAAU;AAAA,CAAI;AACxD,UAAQ,OAAO,MAAM,yIAA0C;AAG/D,QAAM,UAAU;AAChB,QAAM,YAAY,KAAK,IAAI;AAE3B,SAAO,KAAK,IAAI,IAAI,YAAY,SAAS;AACvC,UAAM,KAAK,eAAe,GAAI;AAE9B,QAAI,WAAW,WAAW;AACxB,YAAM,kBAAkB,MAAM,aAAa,MAAM,KAAK;AACtD,UAAI,CAAC,iBAAiB;AACpB,YAAI,SAAS,mDAAW;AACxB;AAAA,MACF;AAAA,IACF,WAAW,WAAW,SAAS;AAC7B,YAAM,WAAW,MAAM,cAAc,MAAM,KAAK;AAChD,UAAI,UAAU;AACZ,YAAI,SAAS,uCAAS;AACtB;AAAA,MACF;AAAA,IACF,OAAO;AAEL,YAAM,WAAW,MAAM,KAAK,SAAS,MAAM;AACzC,cAAM,YAAY,SAAS,cAAc,sBAAsB;AAC/D,YAAI,CAAC,UAAW,QAAO;AACvB,cAAM,OAAO,UAAU,WAAW,KAAK,KAAK;AAC5C,eAAO,KAAK,SAAS;AAAA,MACvB,CAAC;AACD,UAAI,UAAU;AACZ,YAAI,SAAS,gDAAa;AAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,kFAAiB;AAChC;AAKA,eAAsB,YAAY,MAAY,SAAiB,UAAU,OAAO,UAAU,OAAsB;AAE9G,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,SAAS,+CAAY;AACzB,MAAI,eAAoB;AACxB,aAAW,OAAO,gBAAgB;AAChC,QAAI;AACF,qBAAe,MAAM,KAAK,gBAAgB,KAAK,EAAE,SAAS,KAAM,OAAO,UAAU,CAAC;AAClF,UAAI,cAAc;AAChB,YAAI,SAAS,gDAAa,GAAG,EAAE;AAC/B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAAC;AAAA,EACX;AAEA,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,gBAAgB,WAAW,sCAAsC;AAAA,EAC7E;AAGA,MAAI,SAAS,2DAAc;AAC3B,QAAM,aAAa,MAAM,EAAE,OAAO,KAAK,CAAC;AACxC,QAAM,KAAK,eAAe,GAAG;AAG7B,MAAI,SAAS,8BAAU,OAAO,GAAG;AACjC,QAAM,aAAa,KAAK,OAAO;AAC/B,QAAM,KAAK,eAAe,GAAG;AAG7B,QAAM,cAAc,MAAM,aAAa,UAAU;AACjD,MAAI,CAAC,YAAY,SAAS,OAAO,GAAG;AAElC,QAAI,SAAS,sDAA6B;AAC1C,UAAM,aAAa,MAAM,EAAE,OAAO,KAAK,CAAC;AACxC,UAAM,KAAK,SAAS,MAAM,WAAW;AACrC,UAAM,KAAK,SAAS,KAAK,SAAS,EAAE,OAAO,GAAG,CAAC;AAC/C,UAAM,KAAK,eAAe,GAAG;AAAA,EAC/B;AAGA,MAAI,SAAS,0CAAiB;AAC9B,QAAM,KAAK,SAAS,MAAM,OAAO;AACjC,QAAM,KAAK,eAAe,GAAI;AAG9B,MAAI,MAAM,aAAa,MAAM,OAAO,GAAG;AACrC,QAAI,SAAS;AACX,YAAM,kBAAkB,MAAM,WAAW,OAAO;AAAA,IAClD,OAAO;AACL,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKA,eAAsB,aACpB,MACA,SACA,UAAU,OACV,UAAU,OACK;AACf,QAAM,UAAU,KAAK,IAAI,SAAS,GAAK;AACvC,MAAI,SAAS,kDAAe,UAAU,GAAI,kBAAQ;AAElD,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,UAAU;AACd,MAAI,cAAc;AAClB,MAAI,eAAe;AAEnB,SAAO,KAAK,IAAI,IAAI,YAAY,SAAS;AACvC,UAAM,QAAQ,MAAM,KAAK,SAAS,MAAM;AACtC,YAAM,YAAY,SAAS,cAAc,sBAAsB;AAC/D,UAAI,WAAW;AACb,cAAM,OAAO,UAAU,WAAW,KAAK,KAAK;AAC5C,eAAO;AAAA,UACL,YAAY,KAAK,SAAS;AAAA,UAC1B,WAAW,KAAK;AAAA,UAChB,WAAW,KAAK,UAAU,GAAG,GAAG;AAAA,QAClC;AAAA,MACF;AAEA,YAAM,WAAW,SAAS,cAAc,6BAA6B;AACrE,UAAI,UAAU;AACZ,cAAM,WAAW,SAAS;AAC1B,YAAI,UAAU;AACZ,gBAAM,OAAO,SAAS,WAAW,KAAK,KAAK;AAC3C,iBAAO;AAAA,YACL,YAAY,KAAK,SAAS;AAAA,YAC1B,WAAW,KAAK;AAAA,YAChB,WAAW,KAAK,UAAU,GAAG,GAAG;AAAA,UAClC;AAAA,QACF;AAAA,MACF;AAEA,aAAO,EAAE,YAAY,OAAO,WAAW,GAAG,WAAW,GAAG;AAAA,IAC1D,CAAC;AAED,QAAI,MAAM,cAAc,MAAM,YAAY,GAAG;AAC3C,UAAI,CAAC,cAAc;AACjB,YAAI,SAAS,6DAAgB,MAAM,SAAS,cAAI;AAChD,uBAAe;AAAA,MACjB;AAGA,UAAI,MAAM,cAAc,SAAS;AAC/B;AACA,YAAI,eAAe,GAAG;AACpB,cAAI,SAAS,iDAAc,MAAM,SAAS,cAAI;AAC9C;AAAA,QACF;AAAA,MACF,OAAO;AACL,sBAAc;AACd,kBAAU,MAAM;AAAA,MAClB;AAAA,IACF;AAEA,UAAM,KAAK,eAAe,GAAG;AAAA,EAC/B;AAEA,MAAI,CAAC,cAAc;AACjB,QAAI,MAAM,aAAa,MAAM,OAAO,GAAG;AACrC,UAAI,SAAS;AACX,cAAM,kBAAkB,MAAM,WAAW,OAAO;AAAA,MAClD,OAAO;AACL,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,SAAS;AAClB,YAAM,kBAAkB,MAAM,YAAY,OAAO;AAAA,IACnD,OAAO;AACL,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,KAAK,eAAe,GAAI;AAChC;AAKA,eAAsB,aAAa,MAAY,UAAkB,UAAU,OAAwB;AACjG,MAAI,SAAS,6CAAe;AAE5B,QAAM,QAAQ,MAAM,KAAK,SAAS,CAAC,iBAAyB;AAC1D,UAAM,YAAsB,CAAC;AAG7B,UAAM,YAAY,SAAS,cAAc,sBAAsB;AAC/D,cAAU,KAAK,oBAAoB,CAAC,CAAC,SAAS,EAAE;AAChD,QAAI,WAAW;AACb,YAAM,QAAQ,UAAU,UAAU,IAAI;AACtC,YAAM,eAAe,MAAM,iBAAiB,mDAAmD;AAC/F,iBAAW,QAAQ,aAAc,MAAK,OAAO;AAC7C,YAAM,eAAe,MAAM,iBAAiB,wBAAwB;AACpE,iBAAW,OAAO,aAAc,KAAI,OAAO;AAC3C,YAAM,eAAe,MAAM,iBAAiB,6CAA6C;AACzF,iBAAW,KAAK,aAAc,GAAE,OAAO;AAEvC,YAAM,OAAO,MAAM,WAAW,KAAK,KAAK;AACxC,YAAM,cAAc,KACjB,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,eAAe,EAAE,EACzB,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,cAAc,EAAE,EACxB,KAAK;AAER,UAAI,YAAY,SAAS,GAAG;AAC1B,kBAAU,KAAK,oBAAoB,YAAY,MAAM,QAAQ;AAC7D,eAAO,KAAK,UAAU,EAAE,MAAM,aAAa,OAAO,UAAU,CAAC;AAAA,MAC/D;AAAA,IACF;AAGA,UAAM,kBAAkB,SAAS,iBAAiB,8BAA8B;AAChF,cAAU,KAAK,4BAA4B,gBAAgB,MAAM,EAAE;AACnE,eAAW,aAAa,iBAAiB;AACvC,YAAM,SAAS,UAAU;AACzB,YAAM,cAAc,QAAQ,WAAW,SAAS,KAAK;AACrD,UAAI,YAAY,SAAS,aAAa,KAAK,YAAY,SAAS,SAAS,EAAG;AAC5E,YAAM,OAAO,UAAU,WAAW,KAAK,KAAK;AAC5C,UAAI,KAAK,SAAS,IAAI;AACpB,kBAAU,KAAK,oBAAoB,KAAK,MAAM,QAAQ;AACtD,eAAO,KAAK,UAAU,EAAE,MAAM,OAAO,UAAU,CAAC;AAAA,MAClD;AAAA,IACF;AAGA,UAAM,WAAW,SAAS,cAAc,6BAA6B;AACrE,cAAU,KAAK,2BAA2B,CAAC,CAAC,QAAQ,EAAE;AACtD,QAAI,YAAY,SAAS,SAAS,SAAS,GAAG;AAC5C,YAAM,WAAW,SAAS;AAC1B,UAAI,UAAU;AACZ,cAAM,QAAQ,SAAS,UAAU,IAAI;AACrC,cAAM,WAAW,MAAM,iBAAiB,2EAA2E;AACnH,mBAAW,MAAM,SAAU,IAAG,OAAO;AACrC,cAAM,OAAO,MAAM,WAAW,KAAK,KAAK;AACxC,YAAI,KAAK,SAAS,GAAG;AACnB,oBAAU,KAAK,oBAAoB,KAAK,MAAM,QAAQ;AACtD,iBAAO,KAAK,UAAU,EAAE,MAAM,OAAO,UAAU,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,WAAW,SAAS,KAAK;AAC/B,UAAM,QAAQ,SAAS,MAAM,IAAI,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC,EAAE,OAAO,OAAK,EAAE,SAAS,CAAC;AAC9E,UAAM,UAAU,oBAAI,IAAI;AAAA,MACtB;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAS;AAAA,MACxC;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAO;AAAA,MACnC;AAAA,MAAsB;AAAA,IACxB,CAAC;AACD,UAAM,mBAAmB;AAAA,MACvB;AAAA,MAAW;AAAA,MAAQ;AAAA,IACrB;AAEA,UAAM,WAAW,MAAM,UAAU,OAAK,MAAM,gBAAgB,EAAE,SAAS,YAAY,CAAC;AACpF,cAAU,KAAK,cAAc,QAAQ,YAAY,MAAM,MAAM,EAAE;AAE/D,QAAI,YAAY,GAAG;AACjB,YAAM,aAAuB,CAAC;AAC9B,eAAS,IAAI,WAAW,GAAG,IAAI,MAAM,QAAQ,KAAK;AAChD,cAAM,OAAO,MAAM,CAAC;AACpB,YAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,YAAI,iBAAiB,KAAK,QAAM,KAAK,SAAS,EAAE,CAAC,EAAG;AACpD,YAAI,KAAK,WAAW,cAAI,KAAK,KAAK,SAAS,oBAAK,EAAG;AACnD,YAAI,KAAK,MAAM,WAAW,EAAG;AAC7B,YAAI,KAAK,SAAS,EAAG,YAAW,KAAK,IAAI;AACzC,YAAI,SAAS,kBAAQ,SAAS,kBAAQ,KAAK,SAAS,kCAAS,EAAG;AAAA,MAClE;AACA,UAAI,WAAW,SAAS,GAAG;AACzB,kBAAU,KAAK,oBAAoB,WAAW,MAAM,QAAQ;AAC5D,eAAO,KAAK,UAAU,EAAE,MAAM,WAAW,KAAK,IAAI,GAAG,OAAO,UAAU,CAAC;AAAA,MACzE;AAAA,IACF;AAEA,cAAU,KAAK,oBAAoB;AACnC,WAAO,KAAK,UAAU,EAAE,MAAM,IAAI,OAAO,UAAU,CAAC;AAAA,EACtD,GAAG,QAAQ;AAEX,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,KAAK;AAAA,EAC3B,QAAQ;AACN,aAAS,EAAE,MAAM,OAAO,OAAO,CAAC,EAAE;AAAA,EACpC;AAEA,aAAW,QAAQ,OAAO,OAAO;AAC/B,QAAI,SAAS,eAAe,IAAI,EAAE;AAAA,EACpC;AAEA,MAAI,OAAO,QAAQ,OAAO,KAAK,SAAS,GAAG;AACzC,QAAI,SAAS,2DAAc,OAAO,KAAK,MAAM,eAAK;AAClD,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,IAAI,gBAAgB,WAAW,iCAAiC;AACxE;;;AFreA,IAAM,sBAAsB,KAAK,KAAK,GAAG,QAAQ,GAAG,wBAAwB,SAAS;AAM9E,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAAqD;AAC/D,SAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAEA,SAAK,aAAa,KAAK,QAAQ,cAAc;AAE7C,SAAK,UAAU,SAAS,WAAW;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,UAAkB,UAAU,OAAwB;AAC5D,WAAO,KAAK,WAAW,UAAU,OAAO;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,WAAW,UAAkB,SAAmC;AAE5E,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc;AAAA,MAC5C,YAAY,KAAK;AAAA,MACjB,UAAU,CAAC;AAAA,MACX,SAAS,KAAK,QAAQ;AAAA,MACtB,SAAS,KAAK;AAAA,IAChB,CAAC;AAED,QAAI;AAEF,YAAM,gBAAgB,MAAM,KAAK,OAAO;AAGxC,YAAM,aAAa,MAAM,cAAc,MAAM,KAAK,OAAO;AAEzD,UAAI,CAAC,YAAY;AACf,YAAI,SAAS;AACX,gBAAM,kBAAkB,MAAM,SAAS,KAAK,OAAO;AAAA,QACrD,OAAO;AACL,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,YAAY,MAAM,UAAU,KAAK,SAAS,OAAO;AAGvD,YAAM,aAAa,MAAM,KAAK,QAAQ,SAAS,KAAK,SAAS,OAAO;AAGpE,YAAM,QAAQ,MAAM,aAAa,MAAM,UAAU,KAAK,OAAO;AAE7D,aAAO;AAAA,IACT,UAAE;AACA,YAAM,aAAa,SAAS,KAAK,OAAO;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAuB;AAE3B,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc;AAAA,MAC5C,YAAY,KAAK;AAAA,MACjB,UAAU;AAAA,MACV,SAAS;AAAA,MACT,SAAS,KAAK;AAAA,IAChB,CAAC;AAED,QAAI;AACF,YAAM,gBAAgB,MAAM,KAAK,OAAO;AAGxC,cAAQ,OAAO,MAAM,oTAAoE;AACzF,cAAQ,OAAO,MAAM,mFAAkE;AACvF,cAAQ,OAAO,MAAM,4EAAkE;AACvF,cAAQ,OAAO,MAAM,6EAAmE;AACxF,cAAQ,OAAO,MAAM,4EAAkE;AACvF,cAAQ,OAAO,MAAM,oTAAoE;AAGzF,YAAM,KAAK,aAAa;AAExB,cAAQ,OAAO,MAAM,0DAAqD;AAG1E,YAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAI,CAAC;AAAA,IACxD,UAAE;AACA,YAAM,aAAa,SAAS,KAAK,OAAO;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAA8B;AAC1C,UAAM,WAAW,MAAM,OAAO,UAAU;AACxC,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,YAAM,KAAK,SAAS,gBAAgB;AAAA,QAClC,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,MAClB,CAAC;AACD,SAAG,SAAS,8BAA8B,MAAM;AAC9C,WAAG,MAAM;AACT,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,UAAMA,MAAK,MAAM,OAAO,aAAa;AACrC,QAAI;AACF,YAAMA,IAAG,GAAG,KAAK,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IAC/D,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAqD;AACnD,UAAMA,MAAK,UAAQ,IAAI;AACvB,WAAO;AAAA,MACL,UAAUA,IAAG,WAAW,KAAK,UAAU;AAAA,MACvC,aAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;;;AGpKO,SAAS,YAAkB;AAChC,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAqCb;AACD;AAcO,SAAS,aAAa,MAA4B;AACvD,QAAM,SAAqB;AAAA,IACzB,SAAS;AAAA,EACX;AAEA,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAElB,QAAI,QAAQ,UAAU;AACpB,aAAO,UAAU;AACjB,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,OAAO;AACjB,aAAO,UAAU;AACjB,UAAI,IAAI,IAAI,KAAK,UAAU,CAAC,KAAK,IAAI,CAAC,EAAE,WAAW,IAAI,GAAG;AACxD,eAAO,WAAW,KAAK,IAAI,CAAC;AAC5B;AAAA,MACF;AAAA,IACF;AAEA,QAAI,QAAQ,UAAU;AACpB,aAAO,UAAU;AAAA,IACnB;AAEA,QAAI,QAAQ,SAAS;AACnB,aAAO,UAAU;AAAA,IACnB;AAEA,QAAI,QAAQ,SAAS;AACnB,aAAO,UAAU;AAAA,IACnB;AAEA,QAAI,QAAQ,aAAa;AACvB,UAAI,IAAI,IAAI,KAAK,QAAQ;AACvB,eAAO,UAAU,SAAS,KAAK,IAAI,CAAC,GAAG,EAAE;AACzC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,QAAQ,aAAa;AACvB,aAAO,UAAU;AAAA,IACnB;AAEA,QAAI,QAAQ,aAAa;AACvB,aAAO,UAAU;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,gBAAgB,QAA2B;AACzD,SAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AACvC;AAKA,eAAsB,OAAO,MAA+B;AAC1D,QAAM,SAAS,aAAa,IAAI;AAEhC,MAAI,OAAO,YAAY,UAAU,OAAO,YAAY,MAAM;AACxD,cAAU;AACV;AAAA,EACF;AAEA,QAAM,UAAqD,CAAC;AAC5D,MAAI,OAAO,SAAS;AAClB,YAAQ,UAAU,OAAO;AAAA,EAC3B;AACA,MAAI,OAAO,SAAS;AAClB,YAAQ,UAAU;AAAA,EACpB;AAEA,QAAM,QAAQ,IAAI,WAAW,OAAO;AAEpC,MAAI,OAAO,YAAY,SAAS;AAC9B,QAAI;AACF,YAAM,MAAM,MAAM;AAClB,cAAQ,IAAI,gBAAgB;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ,CAAC,CAAC;AAAA,IACJ,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,cAAQ,IAAI,gBAAgB;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC,CAAC;AAAA,IACJ;AACA;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,UAAM,SAAS,MAAM,OAAO;AAC5B,YAAQ,IAAI,gBAAgB;AAAA,MAC1B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ,KAAK,UAAU,MAAM;AAAA,MAC7B,UAAU;AAAA,IACZ,CAAC,CAAC;AACF;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,SAAS;AAC9B,UAAM,MAAM,MAAM;AAClB,YAAQ,IAAI,gBAAgB;AAAA,MAC1B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ,CAAC,CAAC;AACF;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,OAAO;AAC5B,QAAI,CAAC,OAAO,UAAU;AACpB,cAAQ,IAAI,gBAAgB;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC,CAAC;AACF;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI;AACF,YAAM,SAAS,MAAM,MAAM,IAAI,OAAO,UAAU,CAAC,CAAC,OAAO,OAAO;AAChE,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,cAAQ,IAAI,gBAAgB;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU,OAAO;AAAA,QACjB;AAAA,QACA;AAAA,MACF,CAAC,CAAC;AAAA,IACJ,SAAS,OAAO;AACd,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,cAAQ,IAAI,gBAAgB;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU,OAAO;AAAA,QACjB,OAAO;AAAA,QACP;AAAA,MACF,CAAC,CAAC;AAAA,IACJ;AACA;AAAA,EACF;AACF;AAGA,IAAM,aAAa,QAAQ,KAAK,CAAC,GAAG,QAAQ,OAAO,GAAG;AACtD,IAAM,YAAY,YAAY,IAAI,QAAQ,cAAc,EAAE;AAC1D,IAAI,eAAe,cAAc,cAAc,cAAc,MAAM,aAAa;AAC9E,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,SAAO,IAAI,EAAE,MAAM,QAAQ,KAAK;AAClC;","names":["fs"]}
package/dist/index.js CHANGED
@@ -7,8 +7,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
7
7
  });
8
8
 
9
9
  // src/agent.ts
10
- import path2 from "path";
11
- import os2 from "os";
10
+ import path from "path";
11
+ import os from "os";
12
12
 
13
13
  // src/types.ts
14
14
  var YiyanAgentError = class extends Error {
@@ -29,8 +29,6 @@ var YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
29
29
 
30
30
  // src/browser.ts
31
31
  import { chromium } from "playwright";
32
- import path from "path";
33
- import os from "os";
34
32
  import fs from "fs";
35
33
  function log(verbose, msg) {
36
34
  if (verbose) {
@@ -180,20 +178,7 @@ async function waitForUserAction(page, reason, verbose = false) {
180
178
  }
181
179
  log(verbose, "\u26A0 \u7B49\u5F85\u7528\u6237\u64CD\u4F5C\u8D85\u65F6\uFF083\u5206\u949F\uFF09");
182
180
  }
183
- async function saveDebugScreenshot(page, name, verbose) {
184
- try {
185
- const debugDir = path.join(os.homedir(), ".yiyan-browser-agent", "debug");
186
- if (!fs.existsSync(debugDir)) {
187
- fs.mkdirSync(debugDir, { recursive: true });
188
- }
189
- const screenshotPath = path.join(debugDir, `${name}-${Date.now()}.png`);
190
- await page.screenshot({ path: screenshotPath, fullPage: true });
191
- log(verbose, `\u8C03\u8BD5\u622A\u56FE\u5DF2\u4FDD\u5B58: ${screenshotPath}`);
192
- } catch {
193
- }
194
- }
195
181
  async function sendMessage(page, message, verbose = false, headful = false) {
196
- await saveDebugScreenshot(page, "before-send", verbose);
197
182
  const inputSelectors = [
198
183
  '[contenteditable="true"][role="textbox"]',
199
184
  '[contenteditable="true"]',
@@ -213,18 +198,15 @@ async function sendMessage(page, message, verbose = false, headful = false) {
213
198
  }
214
199
  }
215
200
  if (!inputElement) {
216
- await saveDebugScreenshot(page, "no-input-found", verbose);
217
201
  throw new YiyanAgentError("NETWORK", "Cannot find the Yiyan chat input box");
218
202
  }
219
203
  log(verbose, "\u70B9\u51FB\u8F93\u5165\u6846\u83B7\u53D6\u7126\u70B9...");
220
204
  await inputElement.click({ force: true });
221
205
  await page.waitForTimeout(500);
222
- await saveDebugScreenshot(page, "after-click", verbose);
223
206
  log(verbose, `\u8F93\u5165\u95EE\u9898: "${message}"`);
224
207
  await inputElement.fill(message);
225
208
  await page.waitForTimeout(500);
226
209
  const filledValue = await inputElement.innerText();
227
- log(verbose, `\u8F93\u5165\u6846\u5185\u5BB9: "${filledValue.substring(0, 50)}"`);
228
210
  if (!filledValue.includes(message)) {
229
211
  log(verbose, "fill \u5931\u8D25\uFF0C\u5C1D\u8BD5 keyboard.type...");
230
212
  await inputElement.click({ force: true });
@@ -232,11 +214,9 @@ async function sendMessage(page, message, verbose = false, headful = false) {
232
214
  await page.keyboard.type(message, { delay: 50 });
233
215
  await page.waitForTimeout(500);
234
216
  }
235
- await saveDebugScreenshot(page, "after-input", verbose);
236
217
  log(verbose, "\u6309 Enter \u53D1\u9001\u6D88\u606F...");
237
218
  await page.keyboard.press("Enter");
238
219
  await page.waitForTimeout(3e3);
239
- await saveDebugScreenshot(page, "after-send", verbose);
240
220
  if (await checkCaptcha(page, verbose)) {
241
221
  if (headful) {
242
222
  await waitForUserAction(page, "captcha", verbose);
@@ -428,7 +408,7 @@ async function extractReply(page, question, verbose = false) {
428
408
  }
429
409
 
430
410
  // src/agent.ts
431
- var DEFAULT_SESSION_DIR = path2.join(os2.homedir(), ".yiyan-browser-agent", "session");
411
+ var DEFAULT_SESSION_DIR = path.join(os.homedir(), ".yiyan-browser-agent", "session");
432
412
  var YiyanAgent = class {
433
413
  options;
434
414
  sessionDir;
@@ -545,11 +525,11 @@ var YiyanAgent = class {
545
525
  };
546
526
 
547
527
  // src/profile.ts
548
- import path3 from "path";
549
- import os3 from "os";
528
+ import path2 from "path";
529
+ import os2 from "os";
550
530
  import fs2 from "fs";
551
- var CONFIG_FILE_PATH = path3.join(os3.homedir(), ".yiyan-browser-agent", "config.json");
552
- var DEFAULT_SESSION_DIR2 = path3.join(os3.homedir(), ".yiyan-browser-agent", "session");
531
+ var CONFIG_FILE_PATH = path2.join(os2.homedir(), ".yiyan-browser-agent", "config.json");
532
+ var DEFAULT_SESSION_DIR2 = path2.join(os2.homedir(), ".yiyan-browser-agent", "session");
553
533
  function readConfig() {
554
534
  try {
555
535
  if (fs2.existsSync(CONFIG_FILE_PATH)) {
@@ -561,7 +541,7 @@ function readConfig() {
561
541
  return {};
562
542
  }
563
543
  function saveConfig(config) {
564
- const configDir = path3.dirname(CONFIG_FILE_PATH);
544
+ const configDir = path2.dirname(CONFIG_FILE_PATH);
565
545
  if (!fs2.existsSync(configDir)) {
566
546
  fs2.mkdirSync(configDir, { recursive: true });
567
547
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/agent.ts","../src/types.ts","../src/browser.ts","../src/profile.ts"],"sourcesContent":["// src/agent.ts\nimport path from 'path';\nimport os from 'os';\nimport {\n YiyanAgentOptions,\n DEFAULT_OPTIONS,\n YiyanAgentError,\n} from './types';\nimport {\n launchBrowser,\n closeBrowser,\n navigateToYiyan,\n sendMessage,\n waitForReply,\n extractReply,\n checkLoggedIn,\n waitForUserAction,\n} from './browser';\n\n/** 默认 session 存储目录 */\nconst DEFAULT_SESSION_DIR = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\n\n/**\n * 文心一言浏览器代理\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport class YiyanAgent {\n private options: Required<YiyanAgentOptions>;\n private sessionDir: string;\n private verbose: boolean;\n\n constructor(options?: YiyanAgentOptions & { verbose?: boolean }) {\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n this.sessionDir = this.options.profileDir || DEFAULT_SESSION_DIR;\n\n this.verbose = options?.verbose ?? false;\n }\n\n /**\n * 发送问题并获取答案\n * @param question 问题文本\n * @param headful 是否使用有头浏览器(可见窗口),默认为 false(headless)\n */\n async ask(question: string, headful = false): Promise<string> {\n return this.executeAsk(question, headful);\n }\n\n /**\n * 执行单次问答\n */\n private async executeAsk(question: string, headful: boolean): Promise<string> {\n // 启动浏览器(使用 Playwright 内置 Chromium)\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: !headful,\n timeout: this.options.timeout,\n verbose: this.verbose,\n });\n\n try {\n // 导航到文心一言\n await navigateToYiyan(page, this.verbose);\n\n // 检查登录状态\n const isLoggedIn = await checkLoggedIn(page, this.verbose);\n\n if (!isLoggedIn) {\n if (headful) {\n await waitForUserAction(page, 'login', this.verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Not logged in. Please run \"yiyan-agent login\" first, or use headed mode.'\n );\n }\n }\n\n // 发送消息\n await sendMessage(page, question, this.verbose, headful);\n\n // 等待回复\n await waitForReply(page, this.options.timeout, this.verbose, headful);\n\n // 提取回复\n const reply = await extractReply(page, question, this.verbose);\n\n return reply;\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 登录文心一言(打开有头浏览器让用户手动登录)\n * 登录成功后,后续的 ask 调用将自动使用登录状态\n */\n async login(): Promise<void> {\n // 启动有头浏览器\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: 60000,\n verbose: this.verbose,\n });\n\n try {\n await navigateToYiyan(page, this.verbose);\n\n // 输出提示信息\n process.stderr.write('\\n[yiyan-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-agent] ║ ║\\n');\n process.stderr.write('[yiyan-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-agent] ✓ Login complete, saving session...\\n');\n\n // 等待一下确保登录状态保存到 session\n await new Promise(resolve => setTimeout(resolve, 3000));\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 等待用户按 Enter\n */\n private async waitForEnter(): Promise<void> {\n const readline = await import('readline');\n return new Promise<void>((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n rl.question('Press ENTER to continue...', () => {\n rl.close();\n resolve();\n });\n });\n }\n\n /**\n * 清除保存的 session\n */\n async reset(): Promise<void> {\n const fs = await import('fs/promises');\n try {\n await fs.rm(this.sessionDir, { recursive: true, force: true });\n } catch {\n // 目录不存在,忽略\n }\n }\n\n /**\n * 检查状态\n */\n status(): { loggedIn: boolean; sessionPath: string } {\n const fs = require('fs');\n return {\n loggedIn: fs.existsSync(this.sessionDir),\n sessionPath: this.sessionDir,\n };\n }\n}","/**\n * yiyan-browser-agent 类型定义\n */\n\n/** 配置选项 */\nexport interface YiyanAgentOptions {\n /** 超时毫秒,默认 120000 */\n timeout?: number;\n /** 重试次数,默认 3 */\n retryCount?: number;\n /** 自定义 profile 目录 */\n profileDir?: string;\n /** 自定义 Chrome 可执行文件路径 */\n chromePath?: string;\n}\n\n/** CLI 输出格式 */\nexport interface CliOutput {\n success: boolean;\n /** 用户发送的问题 */\n question: string;\n /** 成功时有值 */\n answer?: string;\n /** 失败时有值 */\n error?: string;\n /** 耗时毫秒 */\n duration: number;\n}\n\n/** 错误类型 */\nexport type YiyanAgentErrorType =\n | 'BROWSER_LAUNCH'\n | 'PROFILE_COPY'\n | 'TIMEOUT'\n | 'NETWORK'\n | 'CAPTCHA';\n\n/** 自定义错误类 */\nexport class YiyanAgentError extends Error {\n constructor(\n public type: YiyanAgentErrorType,\n message: string\n ) {\n super(message);\n this.name = 'YiyanAgentError';\n }\n}\n\n/** 默认配置 */\nexport const DEFAULT_OPTIONS: Required<YiyanAgentOptions> = {\n timeout: 120000,\n retryCount: 3,\n profileDir: '',\n chromePath: '',\n};\n\n/** 文心一言网页 URL */\nexport const YIYAN_CHAT_URL = 'https://yiyan.baidu.com/';\n","// src/browser.ts — Playwright controller for Yiyan (文心一言)\nimport { chromium, Page, BrowserContext } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n/** 日志输出(仅 verbose 模式) */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-agent] ${msg}\\n`);\n }\n}\n\n/**\n * 启动浏览器(使用 Playwright 内置 Chromium)\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport async function launchBrowser(\n options: {\n sessionDir: string;\n headless: boolean;\n timeout?: number;\n verbose?: boolean;\n }\n): Promise<{ context: BrowserContext; page: Page }> {\n const { sessionDir, headless, timeout = 30000, verbose = false } = options;\n\n try {\n log(verbose, '启动 Chromium 浏览器...');\n\n // 确保 session 目录存在\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\n // 使用 launchPersistentContext,类似 deepseek-browser-agent\n const context = await chromium.launchPersistentContext(sessionDir, {\n headless,\n viewport: { width: 1280, height: 900 },\n userAgent: [\n 'Mozilla/5.0 (X11; Linux x86_64)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/124.0.0.0 Safari/537.36',\n ].join(' '),\n args: [\n '--disable-blink-features=AutomationControlled',\n '--no-first-run',\n '--no-default-browser-check',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n });\n\n // 设置超时\n context.setDefaultTimeout(timeout);\n\n // 获取或创建页面\n const pages = context.pages();\n const page = pages.length > 0 ? pages[0] : await context.newPage();\n\n // 隐藏自动化信号\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', { get: () => false });\n });\n\n log(verbose, '浏览器启动完成');\n return { context, page };\n } catch (error) {\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 关闭浏览器\n */\nexport async function closeBrowser(\n context: BrowserContext,\n verbose?: boolean\n): Promise<void> {\n log(!!verbose, '关闭浏览器...');\n try {\n await context.close();\n log(!!verbose, '浏览器已关闭');\n } catch {\n // 忽略关闭错误\n }\n}\n\n/**\n * 导航到文心一言聊天页面\n */\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n log(verbose, '导航到文心一言聊天页面...');\n try {\n await page.goto(YIYAN_CHAT_URL, {\n waitUntil: 'domcontentloaded',\n timeout: 30000,\n });\n await page.waitForTimeout(1500);\n log(verbose, '页面加载完成');\n } catch (err) {\n log(verbose, `导航警告: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * 检测文心一言验证码弹窗\n */\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const captchaIndicators = [\n '请完成下列验证后继续',\n '按住左边按钮拖动',\n '滑动验证',\n '点击验证',\n '安全验证',\n 'captcha',\n '请完成验证',\n ];\n\n const hasCaptcha = await page.evaluate((indicators) => {\n const bodyText = document.body.innerText || '';\n for (const indicator of indicators) {\n if (bodyText.includes(indicator)) return true;\n }\n // 检查是否有弹窗/遮罩层\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n if (dialogs.length > 0) return true;\n return false;\n }, captchaIndicators);\n\n if (hasCaptcha) {\n log(verbose, '⚠ 检测到验证码弹窗!');\n }\n return hasCaptcha;\n}\n\n/**\n * 检测是否已登录文心一言\n */\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n const isLoggedIn = await page.evaluate(() => {\n // 文心一言未登录时:页面有\"登录\"按钮和\"未登录\"文字\n const bodyText = document.body.innerText || '';\n\n // 如果有\"未登录\"文字 = 未登录\n if (bodyText.includes('未登录')) return false;\n\n // 检查是否有\"登录\"按钮\n const loginButtons = document.querySelectorAll('button');\n for (const btn of loginButtons) {\n const text = btn.textContent?.trim() || '';\n if (text === '登录') {\n return false; // 有登录按钮 = 未登录\n }\n }\n\n // 如果没有\"登录\"按钮和\"未登录\"文字,说明已登录\n return true;\n });\n\n if (isLoggedIn) {\n log(verbose, '✓ 已检测到登录状态');\n } else {\n log(verbose, '⚠ 未检测到登录状态');\n }\n return isLoggedIn;\n}\n\n/**\n * 有头模式下,暂停等待用户手动操作(过验证码/登录)\n */\nexport async function waitForUserAction(\n page: Page,\n reason: 'captcha' | 'login' | 'no-reply',\n verbose = false\n): Promise<void> {\n const reasonText = reason === 'captcha'\n ? '检测到验证码,请在浏览器中手动完成验证'\n : reason === 'login'\n ? '检测到未登录,请在浏览器中手动登录'\n : 'AI 未回复,请检查浏览器是否需要手动操作(验证码/登录)';\n\n process.stderr.write(`\\n[yiyan-agent] ⚠ ${reasonText}\\n`);\n process.stderr.write('[yiyan-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n // 轮询检测问题是否已解决\n const maxWait = 180000; // 最多等 3 分钟\n const startTime = Date.now();\n\n while (Date.now() - startTime < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha') {\n const stillHasCaptcha = await checkCaptcha(page, false);\n if (!stillHasCaptcha) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n } else if (reason === 'login') {\n const loggedIn = await checkLoggedIn(page, false);\n if (loggedIn) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n } else {\n // no-reply:检测 AI 回复是否出现\n const hasReply = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (!answerBox) return false;\n const text = answerBox.innerText?.trim() || '';\n return text.length > 0;\n });\n if (hasReply) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n/**\n * 保存调试截图\n */\nasync function saveDebugScreenshot(page: Page, name: string, verbose: boolean): Promise<void> {\n try {\n const debugDir = path.join(os.homedir(), '.yiyan-browser-agent', 'debug');\n if (!fs.existsSync(debugDir)) {\n fs.mkdirSync(debugDir, { recursive: true });\n }\n const screenshotPath = path.join(debugDir, `${name}-${Date.now()}.png`);\n await page.screenshot({ path: screenshotPath, fullPage: true });\n log(verbose, `调试截图已保存: ${screenshotPath}`);\n } catch {\n // 截图失败不影响主流程\n }\n}\n\n/**\n * 发送消息到文心一言\n */\nexport async function sendMessage(page: Page, message: string, verbose = false, headful = false): Promise<void> {\n // 调试截图:发送前\n await saveDebugScreenshot(page, 'before-send', verbose);\n\n // 文心一言使用 contenteditable div 而不是 textarea\n const inputSelectors = [\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n 'textarea[placeholder]',\n 'textarea',\n ];\n\n log(verbose, '等待输入框出现...');\n let inputElement: any = null;\n for (const sel of inputSelectors) {\n try {\n inputElement = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (inputElement) {\n log(verbose, `✓ 输入框已找到: ${sel}`);\n break;\n }\n } catch {}\n }\n\n if (!inputElement) {\n // 调试截图:找不到输入框\n await saveDebugScreenshot(page, 'no-input-found', verbose);\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击输入框获取焦点\n log(verbose, '点击输入框获取焦点...');\n await inputElement.click({ force: true });\n await page.waitForTimeout(500);\n\n // 调试截图:点击后\n await saveDebugScreenshot(page, 'after-click', verbose);\n\n // 清除现有内容并输入 - 使用 fill 方法更可靠\n log(verbose, `输入问题: \"${message}\"`);\n await inputElement.fill(message);\n await page.waitForTimeout(500);\n\n // 验证输入是否成功\n const filledValue = await inputElement.innerText();\n log(verbose, `输入框内容: \"${filledValue.substring(0, 50)}\"`);\n if (!filledValue.includes(message)) {\n // 如果 fill 失败,尝试 keyboard.type\n log(verbose, 'fill 失败,尝试 keyboard.type...');\n await inputElement.click({ force: true });\n await page.keyboard.press('Control+a');\n await page.keyboard.type(message, { delay: 50 });\n await page.waitForTimeout(500);\n }\n\n // 调试截图:输入后\n await saveDebugScreenshot(page, 'after-input', verbose);\n\n // 按 Enter 发送\n log(verbose, '按 Enter 发送消息...');\n await page.keyboard.press('Enter');\n await page.waitForTimeout(3000);\n\n // 调试截图:发送后\n await saveDebugScreenshot(page, 'after-send', verbose);\n\n // 检查是否触发了验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha. Use --headful to manually solve it.'\n );\n }\n }\n}\n\n/**\n * 等待回复完成\n */\nexport async function waitForReply(\n page: Page,\n timeout: number,\n verbose = false,\n headful = false\n): Promise<void> {\n const maxWait = Math.min(timeout, 60000);\n log(verbose, `等待 AI 回复(最多 ${maxWait / 1000} 秒)...`);\n\n const startTime = Date.now();\n let lastLen = 0;\n let stableCount = 0;\n let replyStarted = false;\n\n while (Date.now() - startTime < maxWait) {\n const state = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (answerBox) {\n const text = answerBox.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n if (cardList) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const text = lastCard.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n }\n\n return { hasAiReply: false, aiTextLen: 0, aiPreview: '' };\n });\n\n if (state.hasAiReply && state.aiTextLen > 0) {\n if (!replyStarted) {\n log(verbose, `✓ AI 回复已开始生成(${state.aiTextLen}字)`);\n replyStarted = true;\n }\n\n // 文本长度不再变化 → 回复完成\n if (state.aiTextLen === lastLen) {\n stableCount++;\n if (stableCount >= 3) {\n log(verbose, `✓ AI 回复已完成(${state.aiTextLen}字)`);\n break;\n }\n } else {\n stableCount = 0;\n lastLen = state.aiTextLen;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n if (!replyStarted) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha.'\n );\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError(\n 'TIMEOUT',\n 'AI reply timeout in headless mode. Try running login first, or use headed mode.'\n );\n }\n }\n\n // 额外等待确保渲染完成\n await page.waitForTimeout(1000);\n}\n\n/**\n * 提取回复内容\n */\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复内容...');\n\n const reply = await page.evaluate((userQuestion: string) => {\n const debugInfo: string[] = [];\n\n // 方法1:answerBox 中排除思考过程\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n debugInfo.push(`answerBox found: ${!!answerBox}`);\n if (answerBox) {\n const clone = answerBox.cloneNode(true) as HTMLElement;\n const processItems = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"]');\n for (const item of processItems) item.remove();\n const toolMessages = clone.querySelectorAll('[class*=\"toolMessage\"]');\n for (const msg of toolMessages) msg.remove();\n const thinkHeaders = clone.querySelectorAll('[class*=\"headerMask\"], [class*=\"topHeader\"]');\n for (const h of thinkHeaders) h.remove();\n\n const text = clone.innerText?.trim() || '';\n const cleanedText = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/^准备输出结果\\s*/, '')\n .trim();\n\n if (cleanedText.length > 0) {\n debugInfo.push(`method1 success: ${cleanedText.length} chars`);\n return JSON.stringify({ text: cleanedText, debug: debugInfo });\n }\n }\n\n // 方法2:mdRenderContainer\n const allMdContainers = document.querySelectorAll('[class*=\"mdRenderContainer\"]');\n debugInfo.push(`mdRenderContainer count: ${allMdContainers.length}`);\n for (const container of allMdContainers) {\n const parent = container.parentElement;\n const parentClass = parent?.className?.toString() || '';\n if (parentClass.includes('toolMessage') || parentClass.includes('process')) continue;\n const text = container.innerText?.trim() || '';\n if (text.length > 10) {\n debugInfo.push(`method2 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n\n // 方法3:dialogueCardList\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n debugInfo.push(`dialogueCardList found: ${!!cardList}`);\n if (cardList && cardList.children.length > 0) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const clone = lastCard.cloneNode(true) as HTMLElement;\n const thinkEls = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"], [class*=\"toolMessage\"]');\n for (const el of thinkEls) el.remove();\n const text = clone.innerText?.trim() || '';\n if (text.length > 0) {\n debugInfo.push(`method3 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n }\n\n // 方法4:页面文本解析\n const fullText = document.body.innerText;\n const lines = fullText.split('\\n').map(l => l.trim()).filter(l => l.length > 0);\n const uiWords = new Set([\n '文心一言', '新对话', '创意写作', '智慧绘图', '超级智能体', '更多',\n '我的收藏', '项目', '对话', '暂无记录', '未登录', '登录',\n '内容由AI生成,仅供参考,请仔细甄别', '参考',\n ]);\n const thinkingKeywords = [\n '深度思考已完成', '思考完成', '准备输出结果',\n ];\n\n const userQIdx = lines.findIndex(l => l === userQuestion || l.includes(userQuestion));\n debugInfo.push(`userQ idx: ${userQIdx}, lines: ${lines.length}`);\n\n if (userQIdx >= 0) {\n const replyLines: string[] = [];\n for (let i = userQIdx + 1; i < lines.length; i++) {\n const line = lines[i];\n if (uiWords.has(line)) continue;\n if (thinkingKeywords.some(kw => line.includes(kw))) continue;\n if (line.startsWith('搜索') || line.includes('篇资料')) continue;\n if (line.match(/^参考\\d+个网页/)) continue;\n if (line.length > 0) replyLines.push(line);\n if (line === '快速' || line === '更多' || line.includes('内容由AI生成')) break;\n }\n if (replyLines.length > 0) {\n debugInfo.push(`method4 success: ${replyLines.length} lines`);\n return JSON.stringify({ text: replyLines.join('\\n'), debug: debugInfo });\n }\n }\n\n debugInfo.push('ALL METHODS FAILED');\n return JSON.stringify({ text: '', debug: debugInfo });\n }, question);\n\n let parsed: { text: string; debug: string[] };\n try {\n parsed = JSON.parse(reply);\n } catch {\n parsed = { text: reply, debug: [] };\n }\n\n for (const line of parsed.debug) {\n log(verbose, ` [extract] ${line}`);\n }\n\n if (parsed.text && parsed.text.length > 0) {\n log(verbose, `提取成功,回复长度: ${parsed.text.length} 字符`);\n return parsed.text;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply content');\n}","// src/profile.ts — Session management (simplified)\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\nimport fsp from 'fs/promises';\nimport { YiyanAgentError } from './types';\n\n/** 配置文件路径 */\nexport const CONFIG_FILE_PATH = path.join(os.homedir(), '.yiyan-browser-agent', 'config.json');\n\n/** 配置结构 */\nexport interface YiyanConfig {\n chromePath?: string; // 保留但不再使用(向后兼容)\n}\n\n/** 默认 session 目录 */\nexport const DEFAULT_SESSION_DIR = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\n\n/**\n * 读取配置文件\n */\nexport function readConfig(): YiyanConfig {\n try {\n if (fs.existsSync(CONFIG_FILE_PATH)) {\n const content = fs.readFileSync(CONFIG_FILE_PATH, 'utf-8');\n return JSON.parse(content);\n }\n } catch {\n // 配置文件损坏或不存在,返回空配置\n }\n return {};\n}\n\n/**\n * 保存配置文件\n */\nexport function saveConfig(config: YiyanConfig): void {\n const configDir = path.dirname(CONFIG_FILE_PATH);\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true });\n }\n fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2));\n}\n\n/**\n * 检查 session 是否存在\n */\nexport function sessionExists(sessionDir: string): boolean {\n return fs.existsSync(sessionDir);\n}\n\n/**\n * 清除 session\n */\nexport async function clearSession(sessionDir: string): Promise<void> {\n try {\n await fsp.rm(sessionDir, { recursive: true, force: true });\n } catch {\n // 目录不存在,忽略\n }\n}\n\n// ===== 以下函数保留向后兼容,但不再使用 =====\n\n/** Profile 子目录名称(已废弃) */\nconst PROFILE_TARGET_NAME = 'chrome-profile';\n\n/**\n * 检查 profile 是否存在(已废弃,保留向后兼容)\n */\nexport function profileExists(profileDir: string): boolean {\n const targetPath = path.join(profileDir, PROFILE_TARGET_NAME);\n return fs.existsSync(targetPath) || fs.existsSync(profileDir);\n}\n\n/**\n * 清除复制的 profile(已废弃,保留向后兼容)\n */\nexport async function clearCopiedProfile(profileDir: string): Promise<void> {\n const targetPath = path.join(profileDir, PROFILE_TARGET_NAME);\n if (fs.existsSync(targetPath)) {\n await fsp.rm(targetPath, { recursive: true, force: true });\n }\n}\n\n/**\n * Linux 上常见的 Chrome 可执行文件路径(已废弃)\n */\nexport function detectLinuxChromePath(): string | null {\n const paths = [\n '/usr/bin/google-chrome-stable',\n '/usr/bin/google-chrome',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/google-chrome',\n ];\n for (const p of paths) {\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\n/**\n * 获取 Chrome 可执行文件路径(已废弃)\n */\nexport function getChromeExecutablePath(platform: NodeJS.Platform, userPath?: string): string | null {\n return null;\n}\n\n/**\n * 获取 Chrome 用户数据目录路径(已废弃)\n */\nexport function getChromeProfilePath(platform: NodeJS.Platform): string | null {\n return null;\n}\n\n/**\n * 复制 Chrome profile(已废弃)\n */\nexport async function copyChromeProfile(\n platform: NodeJS.Platform,\n targetBaseDir: string\n): Promise<string> {\n return targetBaseDir;\n}"],"mappings":"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","names":["path","os","path","os","fs","path","os","fs","path","os","DEFAULT_SESSION_DIR","fs"]}
1
+ {"version":3,"sources":["../src/agent.ts","../src/types.ts","../src/browser.ts","../src/profile.ts"],"sourcesContent":["// src/agent.ts\nimport path from 'path';\nimport os from 'os';\nimport {\n YiyanAgentOptions,\n DEFAULT_OPTIONS,\n YiyanAgentError,\n} from './types';\nimport {\n launchBrowser,\n closeBrowser,\n navigateToYiyan,\n sendMessage,\n waitForReply,\n extractReply,\n checkLoggedIn,\n waitForUserAction,\n} from './browser';\n\n/** 默认 session 存储目录 */\nconst DEFAULT_SESSION_DIR = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\n\n/**\n * 文心一言浏览器代理\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport class YiyanAgent {\n private options: Required<YiyanAgentOptions>;\n private sessionDir: string;\n private verbose: boolean;\n\n constructor(options?: YiyanAgentOptions & { verbose?: boolean }) {\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n this.sessionDir = this.options.profileDir || DEFAULT_SESSION_DIR;\n\n this.verbose = options?.verbose ?? false;\n }\n\n /**\n * 发送问题并获取答案\n * @param question 问题文本\n * @param headful 是否使用有头浏览器(可见窗口),默认为 false(headless)\n */\n async ask(question: string, headful = false): Promise<string> {\n return this.executeAsk(question, headful);\n }\n\n /**\n * 执行单次问答\n */\n private async executeAsk(question: string, headful: boolean): Promise<string> {\n // 启动浏览器(使用 Playwright 内置 Chromium)\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: !headful,\n timeout: this.options.timeout,\n verbose: this.verbose,\n });\n\n try {\n // 导航到文心一言\n await navigateToYiyan(page, this.verbose);\n\n // 检查登录状态\n const isLoggedIn = await checkLoggedIn(page, this.verbose);\n\n if (!isLoggedIn) {\n if (headful) {\n await waitForUserAction(page, 'login', this.verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Not logged in. Please run \"yiyan-agent login\" first, or use headed mode.'\n );\n }\n }\n\n // 发送消息\n await sendMessage(page, question, this.verbose, headful);\n\n // 等待回复\n await waitForReply(page, this.options.timeout, this.verbose, headful);\n\n // 提取回复\n const reply = await extractReply(page, question, this.verbose);\n\n return reply;\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 登录文心一言(打开有头浏览器让用户手动登录)\n * 登录成功后,后续的 ask 调用将自动使用登录状态\n */\n async login(): Promise<void> {\n // 启动有头浏览器\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: 60000,\n verbose: this.verbose,\n });\n\n try {\n await navigateToYiyan(page, this.verbose);\n\n // 输出提示信息\n process.stderr.write('\\n[yiyan-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-agent] ║ ║\\n');\n process.stderr.write('[yiyan-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-agent] ✓ Login complete, saving session...\\n');\n\n // 等待一下确保登录状态保存到 session\n await new Promise(resolve => setTimeout(resolve, 3000));\n } finally {\n await closeBrowser(context, this.verbose);\n }\n }\n\n /**\n * 等待用户按 Enter\n */\n private async waitForEnter(): Promise<void> {\n const readline = await import('readline');\n return new Promise<void>((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n rl.question('Press ENTER to continue...', () => {\n rl.close();\n resolve();\n });\n });\n }\n\n /**\n * 清除保存的 session\n */\n async reset(): Promise<void> {\n const fs = await import('fs/promises');\n try {\n await fs.rm(this.sessionDir, { recursive: true, force: true });\n } catch {\n // 目录不存在,忽略\n }\n }\n\n /**\n * 检查状态\n */\n status(): { loggedIn: boolean; sessionPath: string } {\n const fs = require('fs');\n return {\n loggedIn: fs.existsSync(this.sessionDir),\n sessionPath: this.sessionDir,\n };\n }\n}","/**\n * yiyan-browser-agent 类型定义\n */\n\n/** 配置选项 */\nexport interface YiyanAgentOptions {\n /** 超时毫秒,默认 120000 */\n timeout?: number;\n /** 重试次数,默认 3 */\n retryCount?: number;\n /** 自定义 profile 目录 */\n profileDir?: string;\n /** 自定义 Chrome 可执行文件路径 */\n chromePath?: string;\n}\n\n/** CLI 输出格式 */\nexport interface CliOutput {\n success: boolean;\n /** 用户发送的问题 */\n question: string;\n /** 成功时有值 */\n answer?: string;\n /** 失败时有值 */\n error?: string;\n /** 耗时毫秒 */\n duration: number;\n}\n\n/** 错误类型 */\nexport type YiyanAgentErrorType =\n | 'BROWSER_LAUNCH'\n | 'PROFILE_COPY'\n | 'TIMEOUT'\n | 'NETWORK'\n | 'CAPTCHA';\n\n/** 自定义错误类 */\nexport class YiyanAgentError extends Error {\n constructor(\n public type: YiyanAgentErrorType,\n message: string\n ) {\n super(message);\n this.name = 'YiyanAgentError';\n }\n}\n\n/** 默认配置 */\nexport const DEFAULT_OPTIONS: Required<YiyanAgentOptions> = {\n timeout: 120000,\n retryCount: 3,\n profileDir: '',\n chromePath: '',\n};\n\n/** 文心一言网页 URL */\nexport const YIYAN_CHAT_URL = 'https://yiyan.baidu.com/';\n","// src/browser.ts — Playwright controller for Yiyan (文心一言)\nimport { chromium, Page, BrowserContext } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n/** 日志输出(仅 verbose 模式) */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-agent] ${msg}\\n`);\n }\n}\n\n/**\n * 启动浏览器(使用 Playwright 内置 Chromium)\n * 参考 deepseek-browser-agent 的实现方式\n */\nexport async function launchBrowser(\n options: {\n sessionDir: string;\n headless: boolean;\n timeout?: number;\n verbose?: boolean;\n }\n): Promise<{ context: BrowserContext; page: Page }> {\n const { sessionDir, headless, timeout = 30000, verbose = false } = options;\n\n try {\n log(verbose, '启动 Chromium 浏览器...');\n\n // 确保 session 目录存在\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\n // 使用 launchPersistentContext,类似 deepseek-browser-agent\n const context = await chromium.launchPersistentContext(sessionDir, {\n headless,\n viewport: { width: 1280, height: 900 },\n userAgent: [\n 'Mozilla/5.0 (X11; Linux x86_64)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/124.0.0.0 Safari/537.36',\n ].join(' '),\n args: [\n '--disable-blink-features=AutomationControlled',\n '--no-first-run',\n '--no-default-browser-check',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n });\n\n // 设置超时\n context.setDefaultTimeout(timeout);\n\n // 获取或创建页面\n const pages = context.pages();\n const page = pages.length > 0 ? pages[0] : await context.newPage();\n\n // 隐藏自动化信号\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', { get: () => false });\n });\n\n log(verbose, '浏览器启动完成');\n return { context, page };\n } catch (error) {\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 关闭浏览器\n */\nexport async function closeBrowser(\n context: BrowserContext,\n verbose?: boolean\n): Promise<void> {\n log(!!verbose, '关闭浏览器...');\n try {\n await context.close();\n log(!!verbose, '浏览器已关闭');\n } catch {\n // 忽略关闭错误\n }\n}\n\n/**\n * 导航到文心一言聊天页面\n */\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n log(verbose, '导航到文心一言聊天页面...');\n try {\n await page.goto(YIYAN_CHAT_URL, {\n waitUntil: 'domcontentloaded',\n timeout: 30000,\n });\n await page.waitForTimeout(1500);\n log(verbose, '页面加载完成');\n } catch (err) {\n log(verbose, `导航警告: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * 检测文心一言验证码弹窗\n */\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const captchaIndicators = [\n '请完成下列验证后继续',\n '按住左边按钮拖动',\n '滑动验证',\n '点击验证',\n '安全验证',\n 'captcha',\n '请完成验证',\n ];\n\n const hasCaptcha = await page.evaluate((indicators) => {\n const bodyText = document.body.innerText || '';\n for (const indicator of indicators) {\n if (bodyText.includes(indicator)) return true;\n }\n // 检查是否有弹窗/遮罩层\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n if (dialogs.length > 0) return true;\n return false;\n }, captchaIndicators);\n\n if (hasCaptcha) {\n log(verbose, '⚠ 检测到验证码弹窗!');\n }\n return hasCaptcha;\n}\n\n/**\n * 检测是否已登录文心一言\n */\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n const isLoggedIn = await page.evaluate(() => {\n // 文心一言未登录时:页面有\"登录\"按钮和\"未登录\"文字\n const bodyText = document.body.innerText || '';\n\n // 如果有\"未登录\"文字 = 未登录\n if (bodyText.includes('未登录')) return false;\n\n // 检查是否有\"登录\"按钮\n const loginButtons = document.querySelectorAll('button');\n for (const btn of loginButtons) {\n const text = btn.textContent?.trim() || '';\n if (text === '登录') {\n return false; // 有登录按钮 = 未登录\n }\n }\n\n // 如果没有\"登录\"按钮和\"未登录\"文字,说明已登录\n return true;\n });\n\n if (isLoggedIn) {\n log(verbose, '✓ 已检测到登录状态');\n } else {\n log(verbose, '⚠ 未检测到登录状态');\n }\n return isLoggedIn;\n}\n\n/**\n * 有头模式下,暂停等待用户手动操作(过验证码/登录)\n */\nexport async function waitForUserAction(\n page: Page,\n reason: 'captcha' | 'login' | 'no-reply',\n verbose = false\n): Promise<void> {\n const reasonText = reason === 'captcha'\n ? '检测到验证码,请在浏览器中手动完成验证'\n : reason === 'login'\n ? '检测到未登录,请在浏览器中手动登录'\n : 'AI 未回复,请检查浏览器是否需要手动操作(验证码/登录)';\n\n process.stderr.write(`\\n[yiyan-agent] ⚠ ${reasonText}\\n`);\n process.stderr.write('[yiyan-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n // 轮询检测问题是否已解决\n const maxWait = 180000; // 最多等 3 分钟\n const startTime = Date.now();\n\n while (Date.now() - startTime < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha') {\n const stillHasCaptcha = await checkCaptcha(page, false);\n if (!stillHasCaptcha) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n } else if (reason === 'login') {\n const loggedIn = await checkLoggedIn(page, false);\n if (loggedIn) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n } else {\n // no-reply:检测 AI 回复是否出现\n const hasReply = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (!answerBox) return false;\n const text = answerBox.innerText?.trim() || '';\n return text.length > 0;\n });\n if (hasReply) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n/**\n * 发送消息到文心一言\n */\nexport async function sendMessage(page: Page, message: string, verbose = false, headful = false): Promise<void> {\n // 文心一言使用 contenteditable div 而不是 textarea\n const inputSelectors = [\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n 'textarea[placeholder]',\n 'textarea',\n ];\n\n log(verbose, '等待输入框出现...');\n let inputElement: any = null;\n for (const sel of inputSelectors) {\n try {\n inputElement = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (inputElement) {\n log(verbose, `✓ 输入框已找到: ${sel}`);\n break;\n }\n } catch {}\n }\n\n if (!inputElement) {\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击输入框获取焦点\n log(verbose, '点击输入框获取焦点...');\n await inputElement.click({ force: true });\n await page.waitForTimeout(500);\n\n // 输入内容\n log(verbose, `输入问题: \"${message}\"`);\n await inputElement.fill(message);\n await page.waitForTimeout(500);\n\n // 验证输入是否成功\n const filledValue = await inputElement.innerText();\n if (!filledValue.includes(message)) {\n // 如果 fill 失败,尝试 keyboard.type\n log(verbose, 'fill 失败,尝试 keyboard.type...');\n await inputElement.click({ force: true });\n await page.keyboard.press('Control+a');\n await page.keyboard.type(message, { delay: 50 });\n await page.waitForTimeout(500);\n }\n\n // 按 Enter 发送\n log(verbose, '按 Enter 发送消息...');\n await page.keyboard.press('Enter');\n await page.waitForTimeout(3000);\n\n // 检查是否触发了验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha. Use --headful to manually solve it.'\n );\n }\n }\n}\n\n/**\n * 等待回复完成\n */\nexport async function waitForReply(\n page: Page,\n timeout: number,\n verbose = false,\n headful = false\n): Promise<void> {\n const maxWait = Math.min(timeout, 60000);\n log(verbose, `等待 AI 回复(最多 ${maxWait / 1000} 秒)...`);\n\n const startTime = Date.now();\n let lastLen = 0;\n let stableCount = 0;\n let replyStarted = false;\n\n while (Date.now() - startTime < maxWait) {\n const state = await page.evaluate(() => {\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n if (answerBox) {\n const text = answerBox.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n if (cardList) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const text = lastCard.innerText?.trim() || '';\n return {\n hasAiReply: text.length > 0,\n aiTextLen: text.length,\n aiPreview: text.substring(0, 100),\n };\n }\n }\n\n return { hasAiReply: false, aiTextLen: 0, aiPreview: '' };\n });\n\n if (state.hasAiReply && state.aiTextLen > 0) {\n if (!replyStarted) {\n log(verbose, `✓ AI 回复已开始生成(${state.aiTextLen}字)`);\n replyStarted = true;\n }\n\n // 文本长度不再变化 → 回复完成\n if (state.aiTextLen === lastLen) {\n stableCount++;\n if (stableCount >= 3) {\n log(verbose, `✓ AI 回复已完成(${state.aiTextLen}字)`);\n break;\n }\n } else {\n stableCount = 0;\n lastLen = state.aiTextLen;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n if (!replyStarted) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError(\n 'CAPTCHA',\n 'Yiyan detected automation and triggered a captcha.'\n );\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError(\n 'TIMEOUT',\n 'AI reply timeout in headless mode. Try running login first, or use headed mode.'\n );\n }\n }\n\n // 额外等待确保渲染完成\n await page.waitForTimeout(1000);\n}\n\n/**\n * 提取回复内容\n */\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复内容...');\n\n const reply = await page.evaluate((userQuestion: string) => {\n const debugInfo: string[] = [];\n\n // 方法1:answerBox 中排除思考过程\n const answerBox = document.querySelector('[class*=\"answerBox\"]');\n debugInfo.push(`answerBox found: ${!!answerBox}`);\n if (answerBox) {\n const clone = answerBox.cloneNode(true) as HTMLElement;\n const processItems = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"]');\n for (const item of processItems) item.remove();\n const toolMessages = clone.querySelectorAll('[class*=\"toolMessage\"]');\n for (const msg of toolMessages) msg.remove();\n const thinkHeaders = clone.querySelectorAll('[class*=\"headerMask\"], [class*=\"topHeader\"]');\n for (const h of thinkHeaders) h.remove();\n\n const text = clone.innerText?.trim() || '';\n const cleanedText = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/^准备输出结果\\s*/, '')\n .trim();\n\n if (cleanedText.length > 0) {\n debugInfo.push(`method1 success: ${cleanedText.length} chars`);\n return JSON.stringify({ text: cleanedText, debug: debugInfo });\n }\n }\n\n // 方法2:mdRenderContainer\n const allMdContainers = document.querySelectorAll('[class*=\"mdRenderContainer\"]');\n debugInfo.push(`mdRenderContainer count: ${allMdContainers.length}`);\n for (const container of allMdContainers) {\n const parent = container.parentElement;\n const parentClass = parent?.className?.toString() || '';\n if (parentClass.includes('toolMessage') || parentClass.includes('process')) continue;\n const text = container.innerText?.trim() || '';\n if (text.length > 10) {\n debugInfo.push(`method2 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n\n // 方法3:dialogueCardList\n const cardList = document.querySelector('[class*=\"dialogueCardList\"]');\n debugInfo.push(`dialogueCardList found: ${!!cardList}`);\n if (cardList && cardList.children.length > 0) {\n const lastCard = cardList.lastElementChild as HTMLElement;\n if (lastCard) {\n const clone = lastCard.cloneNode(true) as HTMLElement;\n const thinkEls = clone.querySelectorAll('[class*=\"processItem\"], [class*=\"processContent\"], [class*=\"toolMessage\"]');\n for (const el of thinkEls) el.remove();\n const text = clone.innerText?.trim() || '';\n if (text.length > 0) {\n debugInfo.push(`method3 success: ${text.length} chars`);\n return JSON.stringify({ text, debug: debugInfo });\n }\n }\n }\n\n // 方法4:页面文本解析\n const fullText = document.body.innerText;\n const lines = fullText.split('\\n').map(l => l.trim()).filter(l => l.length > 0);\n const uiWords = new Set([\n '文心一言', '新对话', '创意写作', '智慧绘图', '超级智能体', '更多',\n '我的收藏', '项目', '对话', '暂无记录', '未登录', '登录',\n '内容由AI生成,仅供参考,请仔细甄别', '参考',\n ]);\n const thinkingKeywords = [\n '深度思考已完成', '思考完成', '准备输出结果',\n ];\n\n const userQIdx = lines.findIndex(l => l === userQuestion || l.includes(userQuestion));\n debugInfo.push(`userQ idx: ${userQIdx}, lines: ${lines.length}`);\n\n if (userQIdx >= 0) {\n const replyLines: string[] = [];\n for (let i = userQIdx + 1; i < lines.length; i++) {\n const line = lines[i];\n if (uiWords.has(line)) continue;\n if (thinkingKeywords.some(kw => line.includes(kw))) continue;\n if (line.startsWith('搜索') || line.includes('篇资料')) continue;\n if (line.match(/^参考\\d+个网页/)) continue;\n if (line.length > 0) replyLines.push(line);\n if (line === '快速' || line === '更多' || line.includes('内容由AI生成')) break;\n }\n if (replyLines.length > 0) {\n debugInfo.push(`method4 success: ${replyLines.length} lines`);\n return JSON.stringify({ text: replyLines.join('\\n'), debug: debugInfo });\n }\n }\n\n debugInfo.push('ALL METHODS FAILED');\n return JSON.stringify({ text: '', debug: debugInfo });\n }, question);\n\n let parsed: { text: string; debug: string[] };\n try {\n parsed = JSON.parse(reply);\n } catch {\n parsed = { text: reply, debug: [] };\n }\n\n for (const line of parsed.debug) {\n log(verbose, ` [extract] ${line}`);\n }\n\n if (parsed.text && parsed.text.length > 0) {\n log(verbose, `提取成功,回复长度: ${parsed.text.length} 字符`);\n return parsed.text;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply content');\n}","// src/profile.ts — Session management (simplified)\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\nimport fsp from 'fs/promises';\nimport { YiyanAgentError } from './types';\n\n/** 配置文件路径 */\nexport const CONFIG_FILE_PATH = path.join(os.homedir(), '.yiyan-browser-agent', 'config.json');\n\n/** 配置结构 */\nexport interface YiyanConfig {\n chromePath?: string; // 保留但不再使用(向后兼容)\n}\n\n/** 默认 session 目录 */\nexport const DEFAULT_SESSION_DIR = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\n\n/**\n * 读取配置文件\n */\nexport function readConfig(): YiyanConfig {\n try {\n if (fs.existsSync(CONFIG_FILE_PATH)) {\n const content = fs.readFileSync(CONFIG_FILE_PATH, 'utf-8');\n return JSON.parse(content);\n }\n } catch {\n // 配置文件损坏或不存在,返回空配置\n }\n return {};\n}\n\n/**\n * 保存配置文件\n */\nexport function saveConfig(config: YiyanConfig): void {\n const configDir = path.dirname(CONFIG_FILE_PATH);\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true });\n }\n fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2));\n}\n\n/**\n * 检查 session 是否存在\n */\nexport function sessionExists(sessionDir: string): boolean {\n return fs.existsSync(sessionDir);\n}\n\n/**\n * 清除 session\n */\nexport async function clearSession(sessionDir: string): Promise<void> {\n try {\n await fsp.rm(sessionDir, { recursive: true, force: true });\n } catch {\n // 目录不存在,忽略\n }\n}\n\n// ===== 以下函数保留向后兼容,但不再使用 =====\n\n/** Profile 子目录名称(已废弃) */\nconst PROFILE_TARGET_NAME = 'chrome-profile';\n\n/**\n * 检查 profile 是否存在(已废弃,保留向后兼容)\n */\nexport function profileExists(profileDir: string): boolean {\n const targetPath = path.join(profileDir, PROFILE_TARGET_NAME);\n return fs.existsSync(targetPath) || fs.existsSync(profileDir);\n}\n\n/**\n * 清除复制的 profile(已废弃,保留向后兼容)\n */\nexport async function clearCopiedProfile(profileDir: string): Promise<void> {\n const targetPath = path.join(profileDir, PROFILE_TARGET_NAME);\n if (fs.existsSync(targetPath)) {\n await fsp.rm(targetPath, { recursive: true, force: true });\n }\n}\n\n/**\n * Linux 上常见的 Chrome 可执行文件路径(已废弃)\n */\nexport function detectLinuxChromePath(): string | null {\n const paths = [\n '/usr/bin/google-chrome-stable',\n '/usr/bin/google-chrome',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/google-chrome',\n ];\n for (const p of paths) {\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\n/**\n * 获取 Chrome 可执行文件路径(已废弃)\n */\nexport function getChromeExecutablePath(platform: NodeJS.Platform, userPath?: string): string | null {\n return null;\n}\n\n/**\n * 获取 Chrome 用户数据目录路径(已废弃)\n */\nexport function getChromeProfilePath(platform: NodeJS.Platform): string | null {\n return null;\n}\n\n/**\n * 复制 Chrome profile(已废弃)\n */\nexport async function copyChromeProfile(\n platform: NodeJS.Platform,\n targetBaseDir: string\n): Promise<string> {\n return targetBaseDir;\n}"],"mappings":"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","names":["fs","path","os","fs","path","os","DEFAULT_SESSION_DIR","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "NPM package for interacting with Yiyan (文心一言) web version via Playwright",
5
5
  "type": "module",
6
6
  "bin": {