yiyan-browser-agent 1.4.4 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { C as CliOutput } from './types-BhQ78DYf.js';
3
+
4
+ /** CLI 帮助信息 */
5
+ declare function printHelp(): void;
6
+ /** 解析后的 CLI 参数 */
7
+ interface ParsedArgs {
8
+ command: 'ask' | 'status' | 'reset' | 'login' | 'debug' | 'help' | null;
9
+ question?: string;
10
+ timeout?: number;
11
+ headful?: boolean;
12
+ verbose?: boolean;
13
+ }
14
+ /**
15
+ * 解析 CLI 参数
16
+ */
17
+ declare function parseCliArgs(args: string[]): ParsedArgs;
18
+ /**
19
+ * 格式化 CLI 输出为 JSON
20
+ */
21
+ declare function formatCliOutput(output: CliOutput): string;
22
+ /**
23
+ * CLI 主入口
24
+ */
25
+ declare function runCli(args: string[]): Promise<void>;
26
+
27
+ export { formatCliOutput, parseCliArgs, printHelp, runCli };
package/dist/cli.js CHANGED
@@ -1,15 +1,46 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env node
3
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
- }) : x)(function(x) {
6
- if (typeof require !== "undefined") return require.apply(this, arguments);
7
- throw Error('Dynamic require of "' + x + '" is not supported');
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/cli.ts
32
+ var cli_exports = {};
33
+ __export(cli_exports, {
34
+ formatCliOutput: () => formatCliOutput,
35
+ parseCliArgs: () => parseCliArgs,
36
+ printHelp: () => printHelp,
37
+ runCli: () => runCli
8
38
  });
39
+ module.exports = __toCommonJS(cli_exports);
9
40
 
10
41
  // src/agent.ts
11
- import path from "path";
12
- import os from "os";
42
+ var import_path = __toESM(require("path"));
43
+ var import_os = __toESM(require("os"));
13
44
 
14
45
  // src/types.ts
15
46
  var YiyanAgentError = class extends Error {
@@ -29,8 +60,8 @@ var DEFAULT_OPTIONS = {
29
60
  var YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
30
61
 
31
62
  // src/browser.ts
32
- import { chromium } from "playwright";
33
- import fs from "fs";
63
+ var import_playwright = require("playwright");
64
+ var import_fs = __toESM(require("fs"));
34
65
  var SELECTORS = {
35
66
  // 输入框选择器(按优先级排序)
36
67
  chatInput: [
@@ -80,10 +111,10 @@ async function launchBrowser(options) {
80
111
  const { sessionDir, headless, timeout = 3e4, verbose = false } = options;
81
112
  process.stderr.write("[yiyan-browser-agent] \u542F\u52A8 Chromium \u6D4F\u89C8\u5668...\n");
82
113
  try {
83
- if (!fs.existsSync(sessionDir)) {
84
- fs.mkdirSync(sessionDir, { recursive: true });
114
+ if (!import_fs.default.existsSync(sessionDir)) {
115
+ import_fs.default.mkdirSync(sessionDir, { recursive: true });
85
116
  }
86
- const context = await chromium.launchPersistentContext(sessionDir, {
117
+ const context = await import_playwright.chromium.launchPersistentContext(sessionDir, {
87
118
  headless,
88
119
  viewport: { width: 1280, height: 900 },
89
120
  userAgent: [
@@ -437,7 +468,7 @@ async function dumpDebugInfo(page) {
437
468
  }
438
469
 
439
470
  // src/agent.ts
440
- var DEFAULT_SESSION_DIR = path.join(os.homedir(), ".yiyan-browser-agent", "session");
471
+ var DEFAULT_SESSION_DIR = import_path.default.join(import_os.default.homedir(), ".yiyan-browser-agent", "session");
441
472
  var YiyanAgent = class {
442
473
  options;
443
474
  sessionDir;
@@ -451,7 +482,7 @@ var YiyanAgent = class {
451
482
  };
452
483
  this.sessionDir = this.options.profileDir || DEFAULT_SESSION_DIR;
453
484
  this.verbose = options?.verbose ?? false;
454
- const fs2 = __require("fs");
485
+ const fs2 = require("fs");
455
486
  fs2.mkdirSync(this.sessionDir, { recursive: true });
456
487
  }
457
488
  /**
@@ -561,7 +592,7 @@ var YiyanAgent = class {
561
592
  * 检查状态
562
593
  */
563
594
  status() {
564
- const fs2 = __require("fs");
595
+ const fs2 = require("fs");
565
596
  return {
566
597
  loggedIn: fs2.existsSync(this.sessionDir),
567
598
  sessionPath: this.sessionDir
@@ -816,10 +847,11 @@ runCli(process.argv.slice(2)).catch((err) => {
816
847
  console.error("[yiyan-browser-agent] Uncaught error:", err);
817
848
  process.exit(1);
818
849
  });
819
- export {
850
+ // Annotate the CommonJS export names for ESM import in node:
851
+ 0 && (module.exports = {
820
852
  formatCliOutput,
821
853
  parseCliArgs,
822
854
  printHelp,
823
855
  runCli
824
- };
856
+ });
825
857
  //# sourceMappingURL=cli.js.map
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 dumpDebugInfo,\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 private _context: any = null; // 保存当前 context 以便关闭\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 const fs = require('fs');\n fs.mkdirSync(this.sessionDir, { recursive: true });\n }\n\n /**\n * 关闭浏览器(如果正在运行)\n */\n async close(): Promise<void> {\n if (this._context) {\n try {\n await this._context.close();\n } catch {}\n this._context = null;\n }\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-browser-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-browser-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-browser-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-browser-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 /**\n * Debug 模式:启动浏览器并输出 DOM 信息\n */\n async debug(): Promise<void> {\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: this.options.timeout,\n verbose: true,\n });\n\n try {\n await navigateToYiyan(page, true);\n await page.waitForTimeout(3000);\n await dumpDebugInfo(page);\n\n // 保持浏览器打开,让用户手动测试\n process.stderr.write('\\n[yiyan-browser-agent] 浏览器保持打开,可手动测试。\\n');\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器窗口结束 debug 模式...\\n');\n\n // 等待浏览器关闭\n await new Promise<void>((resolve) => {\n context.on('close', () => resolve());\n });\n } finally {\n // 浏览器已由用户关闭,这里只是清理\n try {\n await context.close();\n } catch {}\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 (文心一言)\n// 参考 deepseek-browser-agent 的实现方式\nimport { chromium, Page, BrowserContext, ElementHandle } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 选择器配置 — 多 fallback 策略,不依赖单一选择器\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SELECTORS = {\n // 输入框选择器(按优先级排序)\n chatInput: [\n '#chat-input',\n 'textarea[placeholder*=\"输入\"]',\n 'textarea[placeholder]',\n 'textarea',\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n ],\n\n // 发送按钮选择器\n sendButton: [\n 'button[aria-label*=\"发送\"]',\n 'button[aria-label*=\"Send\"]',\n '[data-testid=\"send-button\"]',\n 'button[type=\"submit\"]',\n '[class*=\"send-btn\"]',\n '[class*=\"sendBtn\"]',\n '[class*=\"send-button\"]',\n ],\n\n // 响应容器选择器\n responseContainer: [\n '[class*=\"answerBox\"]',\n '[class*=\"response\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"assistant\"]',\n '[class*=\"markdown\"]',\n '[class*=\"message-content\"]',\n '[class*=\"chat-message\"]',\n ],\n\n // 停止生成按钮\n stopButton: [\n 'button[aria-label*=\"停止\"]',\n 'button[aria-label*=\"Stop\"]',\n '[class*=\"stop-btn\"]',\n '[class*=\"stopBtn\"]',\n '[class*=\"stop-gen\"]',\n ],\n};\n\n/** 日志输出 */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-browser-agent] ${msg}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 启动浏览器\n// ─────────────────────────────────────────────────────────────────────────────\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 // 始终输出启动日志(便于排查问题)\n process.stderr.write('[yiyan-browser-agent] 启动 Chromium 浏览器...\\n');\n\n try {\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\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 context.setDefaultTimeout(timeout);\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 process.stderr.write('[yiyan-browser-agent] 浏览器启动完成\\n');\n return { context, page };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[yiyan-browser-agent] ✗ 浏览器启动失败: ${errorMsg}\\n`);\n process.stderr.write('[yiyan-browser-agent] 提示: Ubuntu 需要先运行: npx playwright install-deps chromium\\n');\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${errorMsg}`\n );\n }\n}\n\nexport async function closeBrowser(context: BrowserContext, verbose?: boolean): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器...\\n');\n try {\n await context.close();\n process.stderr.write('[yiyan-browser-agent] 浏览器已关闭\\n');\n } catch {}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 导航\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 导航到文心一言...\\n');\n try {\n await page.goto(YIYAN_CHAT_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });\n await page.waitForTimeout(1500);\n process.stderr.write('[yiyan-browser-agent] 页面加载完成\\n');\n } catch (err) {\n process.stderr.write(`[yiyan-browser-agent] 导航警告: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 登录检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n await page.waitForTimeout(2000);\n\n const isLoggedIn = await page.evaluate(() => {\n const url = window.location.href;\n const bodyText = document.body?.innerText || '';\n\n // URL 包含登录相关路径\n if (url.includes('/auth') || url.includes('/login') || url.includes('/sign')) return false;\n\n // 页面包含登录相关文字\n if (bodyText.includes('未登录') || bodyText.includes('请登录')) return false;\n\n // 存在登录按钮\n if (document.querySelector('input[type=\"password\"]')) return false;\n\n const loginBtn = document.querySelector('button');\n if (loginBtn && loginBtn.textContent?.trim() === '登录') return false;\n\n return true;\n });\n\n process.stderr.write(isLoggedIn ? '[yiyan-browser-agent] ✓ 已检测到登录状态\\n' : '[yiyan-browser-agent] ⚠ 未登录\\n');\n return isLoggedIn;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 验证码检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const hasCaptcha = await page.evaluate(() => {\n const bodyText = document.body.innerText || '';\n const indicators = ['验证码', '请完成验证', '安全验证', '滑动验证', 'captcha'];\n for (const kw of indicators) {\n if (bodyText.includes(kw)) return true;\n }\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n return dialogs.length > 0;\n });\n\n if (hasCaptcha) log(verbose, '⚠ 检测到验证码!');\n return hasCaptcha;\n}\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 messages = {\n captcha: '检测到验证码,请在浏览器中手动完成验证',\n login: '检测到未登录,请在浏览器中手动登录',\n 'no-reply': 'AI 未回复,请检查浏览器是否需要手动操作',\n };\n\n process.stderr.write(`\\n[yiyan-browser-agent] ⚠ ${messages[reason]}\\n`);\n process.stderr.write('[yiyan-browser-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n const maxWait = 180000;\n const start = Date.now();\n\n while (Date.now() - start < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha' && !await checkCaptcha(page, false)) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n if (reason === 'login' && await checkLoggedIn(page, false)) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n if (reason === 'no-reply' && await getMessageCount(page) > 0) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 发送消息 — 参考 deepseek-browser-agent 的实现\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function sendMessage(\n page: Page,\n message: string,\n verbose = false,\n headful = false\n): Promise<void> {\n // 查找输入框\n const input = await findInput(page, verbose);\n if (!input) {\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击获取焦点\n await input.click({ force: true });\n await page.waitForTimeout(200);\n\n // 清除现有内容\n await page.keyboard.press('Control+a');\n await page.waitForTimeout(100);\n\n // 输入内容 — 使用 execCommand(contenteditable 最可靠方式)\n const isTextarea = await input.evaluate(el => el.tagName.toLowerCase() === 'textarea');\n\n if (isTextarea) {\n // textarea 使用 fill\n await input.fill(message);\n } else {\n // contenteditable 使用 execCommand\n await input.evaluate((el, content) => {\n el.focus();\n document.execCommand('selectAll', false, null);\n document.execCommand('delete', false, null);\n document.execCommand('insertText', false, content);\n el.dispatchEvent(new InputEvent('input', { bubbles: true, data: content }));\n }, message);\n }\n\n await page.waitForTimeout(400);\n log(verbose, `已输入问题: \"${message.substring(0, 50)}...\"`);\n\n // 尝试点击发送按钮,失败则按 Enter\n const sent = await clickSendButton(page);\n if (!sent) {\n await page.keyboard.press('Enter');\n }\n\n await page.waitForTimeout(500);\n\n // 检查验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected. Use --headful to solve it.');\n }\n }\n}\n\nasync function findInput(page: Page, verbose = false): Promise<ElementHandle | null> {\n for (const sel of SELECTORS.chatInput) {\n try {\n const el = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (el) {\n log(verbose, `✓ 输入框: ${sel}`);\n return el;\n }\n } catch {}\n }\n return null;\n}\n\nasync function clickSendButton(page: Page): Promise<boolean> {\n for (const sel of SELECTORS.sendButton) {\n try {\n const el = await page.$(sel);\n if (el && await el.isVisible() && await el.isEnabled()) {\n await el.click();\n return true;\n }\n } catch {}\n }\n return false;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 等待回复 — 参考 deepseek-browser-agent 的稳定检测策略\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, 120000);\n const stableDelay = 2500; // 文本稳定 2.5 秒视为完成\n const start = Date.now();\n\n // Phase 1: 等待新消息出现\n const initialCount = await getMessageCount(page);\n let appeared = false;\n\n while (Date.now() - start < 12000) {\n const count = await getMessageCount(page);\n if (count > initialCount) {\n appeared = true;\n log(verbose, '✓ AI 回复已开始生成');\n break;\n }\n await page.waitForTimeout(400);\n }\n\n if (!appeared) {\n log(verbose, '回复可能延迟,继续等待...');\n }\n\n // Phase 2: 等待文本稳定\n let lastText = '';\n let stableStart: number | null = null;\n\n while (Date.now() - start < maxWait) {\n const text = await extractLastMessage(page);\n\n if (text !== lastText) {\n lastText = text;\n stableStart = null;\n } else if (text.length > 0) {\n if (!stableStart) stableStart = Date.now();\n else if (Date.now() - stableStart >= stableDelay) {\n if (!await isGenerating(page)) {\n log(verbose, `✓ AI 回复已完成(${text.length}字)`);\n break;\n }\n stableStart = null;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n // 检查失败情况\n if (lastText.length === 0) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected.');\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError('TIMEOUT', 'AI reply timeout.');\n }\n }\n\n await page.waitForTimeout(1000);\n}\n\nasync function getMessageCount(page: Page): Promise<number> {\n return await page.evaluate(() => {\n for (const sel of [\n '[class*=\"answerBox\"]',\n '[class*=\"assistant\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"response\"]',\n ]) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) return els.length;\n }\n return document.querySelectorAll('[class*=\"message\"]').length;\n });\n}\n\nasync function isGenerating(page: Page): Promise<boolean> {\n return await page.evaluate(() => {\n // 检查停止按钮\n for (const sel of ['button[aria-label*=\"停止\"]', '[class*=\"stop\"]', '[class*=\"generating\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n // 检查加载指示器\n for (const sel of ['[class*=\"loading\"]', '[class*=\"typing\"]', '[class*=\"spinner\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n return false;\n });\n}\n\nasync function extractLastMessage(page: Page): Promise<string> {\n return await page.evaluate(() => {\n function getFullText(el: Element): string {\n if (!el) return '';\n let result = '';\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n result += node.textContent || '';\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const tag = (node as Element).tagName.toLowerCase();\n\n if (tag === 'pre') {\n const codeEl = node.querySelector('code');\n if (codeEl) {\n const cls = codeEl.className || '';\n const lang = (cls.match(/language-(\\S+)/) || [])[1] || '';\n result += '\\n```' + lang + '\\n' + (codeEl.textContent || '') + '\\n```\\n';\n } else {\n result += '\\n```\\n' + (node.textContent || '') + '\\n```\\n';\n }\n return;\n }\n\n for (const child of node.childNodes) walk(child);\n\n if (['p', 'div', 'li', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {\n result += '\\n';\n }\n }\n\n walk(el);\n return result.trim();\n }\n\n // 尝试多个选择器\n for (const sel of SELECTORS.responseContainer) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) {\n const text = getFullText(els[els.length - 1]);\n if (text.length > 10) return text;\n }\n }\n\n // 备选:markdown 容器\n const mdEls = document.querySelectorAll('[class*=\"markdown\"], [class*=\"prose\"]');\n if (mdEls.length > 0) {\n const text = getFullText(mdEls[mdEls.length - 1]);\n if (text.length > 10) return text;\n }\n\n return '';\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 提取回复(简化版)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复...');\n\n const text = await extractLastMessage(page);\n\n if (text.length > 0) {\n const cleaned = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\n log(verbose, `提取成功: ${cleaned.length} 字符`);\n return cleaned;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 调试工具\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function dumpDebugInfo(page: Page): Promise<void> {\n const info = await page.evaluate(() => {\n const classFreq: Record<string, number> = {};\n document.querySelectorAll('*').forEach(el => {\n el.classList.forEach(c => {\n if (c.match(/message|chat|input|send|stop|markdown|content|assistant|user|bot|answer/i)) {\n classFreq[c] = (classFreq[c] || 0) + 1;\n }\n });\n });\n\n const inputs = Array.from(document.querySelectorAll('textarea, [contenteditable]')).map(e => ({\n tag: e.tagName,\n id: e.id || null,\n class: (e.className?.toString() || '').substring(0, 80),\n placeholder: (e as any).placeholder || null,\n editable: e.isContentEditable,\n visible: e.offsetParent !== null,\n }));\n\n return {\n url: window.location.href,\n title: document.title,\n classes: Object.entries(classFreq).sort((a, b) => b[1] - a[1]).slice(0, 40),\n inputs,\n };\n });\n\n console.log('\\n' + '═'.repeat(60));\n console.log(' DOM DEBUG INFO');\n console.log('═'.repeat(60));\n console.log('URL :', info.url);\n console.log('Title :', info.title);\n console.log('\\nInput elements:');\n info.inputs.forEach(i => console.log(' ', JSON.stringify(i)));\n console.log('\\nMatching CSS classes (by frequency):');\n info.classes.forEach(([cls, count]) => console.log(` ${String(count).padStart(3)}x .${cls}`));\n console.log('═'.repeat(60) + '\\n');\n}","#!/usr/bin/env node\n// src/cli.ts — CLI entry point for Yiyan Browser Agent\n// MUST have shebang for npm global install to work\n\nimport { YiyanAgent } from './agent';\nimport { CliOutput, YiyanAgentOptions } from './types';\n\n// 立即输出 banner - 确保用户知道程序正在运行\nconsole.log('');\nconsole.log('╔══════════════════════════════════════════════════╗');\nconsole.log('║ 🤖 Yiyan Browser Agent — 文心一言浏览器代理 ║');\nconsole.log('╚══════════════════════════════════════════════════╝');\nconsole.log('');\n\n/** CLI 帮助信息 */\nexport function printHelp(): void {\n console.log(`\nyiyan-browser-agent - 文心一言浏览器代理 CLI\n\n用法:\n yiyan-browser-agent login 首次登录文心一言(会打开浏览器窗口)\n yiyan-browser-agent ask \"问题\" [--timeout ms] [--headful] [--verbose]\n yiyan-browser-agent status 检查登录状态\n yiyan-browser-agent reset 清除保存的 session\n yiyan-browser-agent debug 调试模式(输出 DOM 信息)\n\n命令:\n login 打开浏览器手动登录文心一言(首次使用必须先登录)\n ask 发送问题并获取答案(默认无头模式,不弹窗;登录后直接使用)\n status 检查登录状态\n reset 清除保存的 session\n debug 调试模式:启动浏览器输出 DOM 信息,用于排查选择器问题\n\n选项:\n --timeout <ms> 超时时间(毫秒),默认 120000\n --headful 使用有头浏览器(可见窗口,用于手动过验证码)\n --verbose 显示详细日志(调试用)\n --help 显示帮助信息\n\n示例:\n yiyan-browser-agent login # 首次使用:登录文心一言\n yiyan-browser-agent ask \"什么是 TypeScript?\" # 提问(静默模式)\n yiyan-browser-agent ask \"解释 Promise\" --verbose # 显示详细日志\n yiyan-browser-agent ask \"30+30=\" --headful # 有头模式(可手动过验证码)\n yiyan-browser-agent debug # 调试模式,输出 DOM 信息\n yiyan-browser-agent status\n yiyan-browser-agent reset\n\n流程:\n 1. 先运行 yiyan-browser-agent login 登录(只需一次,登录状态会保存)\n 2. 之后直接 yiyan-browser-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' | 'debug' | '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 === 'debug') {\n result.command = 'debug';\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 // 设置信号处理\n const shutdown = async () => {\n console.log('\\n[yiyan-browser-agent] 正在关闭...');\n try { await agent.close(); } catch {}\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n if (parsed.command === 'login') {\n try {\n console.log('[yiyan-browser-agent] 启动登录流程...');\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.error('[yiyan-browser-agent] ✗ 登录失败:', errorMessage);\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 === 'debug') {\n try {\n console.log('[yiyan-browser-agent] 启动调试模式...');\n await agent.debug();\n console.log(formatCliOutput({\n success: true,\n question: 'debug',\n answer: 'Debug session completed',\n duration: 0,\n }));\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error('[yiyan-browser-agent] ✗ 调试失败:', errorMessage);\n console.log(formatCliOutput({\n success: false,\n question: 'debug',\n error: errorMessage,\n duration: 0,\n }));\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\nrunCli(process.argv.slice(2)).catch(err => {\n console.error('[yiyan-browser-agent] Uncaught error:', err);\n process.exit(1);\n});"],"mappings":"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","names":["fs"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/agent.ts","../src/types.ts","../src/browser.ts"],"sourcesContent":["#!/usr/bin/env node\n// src/cli.ts — CLI entry point for Yiyan Browser Agent\n// MUST have shebang for npm global install to work\n\nimport { YiyanAgent } from './agent';\nimport { CliOutput, YiyanAgentOptions } from './types';\n\n// 立即输出 banner - 确保用户知道程序正在运行\nconsole.log('');\nconsole.log('╔══════════════════════════════════════════════════╗');\nconsole.log('║ 🤖 Yiyan Browser Agent — 文心一言浏览器代理 ║');\nconsole.log('╚══════════════════════════════════════════════════╝');\nconsole.log('');\n\n/** CLI 帮助信息 */\nexport function printHelp(): void {\n console.log(`\nyiyan-browser-agent - 文心一言浏览器代理 CLI\n\n用法:\n yiyan-browser-agent login 首次登录文心一言(会打开浏览器窗口)\n yiyan-browser-agent ask \"问题\" [--timeout ms] [--headful] [--verbose]\n yiyan-browser-agent status 检查登录状态\n yiyan-browser-agent reset 清除保存的 session\n yiyan-browser-agent debug 调试模式(输出 DOM 信息)\n\n命令:\n login 打开浏览器手动登录文心一言(首次使用必须先登录)\n ask 发送问题并获取答案(默认无头模式,不弹窗;登录后直接使用)\n status 检查登录状态\n reset 清除保存的 session\n debug 调试模式:启动浏览器输出 DOM 信息,用于排查选择器问题\n\n选项:\n --timeout <ms> 超时时间(毫秒),默认 120000\n --headful 使用有头浏览器(可见窗口,用于手动过验证码)\n --verbose 显示详细日志(调试用)\n --help 显示帮助信息\n\n示例:\n yiyan-browser-agent login # 首次使用:登录文心一言\n yiyan-browser-agent ask \"什么是 TypeScript?\" # 提问(静默模式)\n yiyan-browser-agent ask \"解释 Promise\" --verbose # 显示详细日志\n yiyan-browser-agent ask \"30+30=\" --headful # 有头模式(可手动过验证码)\n yiyan-browser-agent debug # 调试模式,输出 DOM 信息\n yiyan-browser-agent status\n yiyan-browser-agent reset\n\n流程:\n 1. 先运行 yiyan-browser-agent login 登录(只需一次,登录状态会保存)\n 2. 之后直接 yiyan-browser-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' | 'debug' | '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 === 'debug') {\n result.command = 'debug';\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 // 设置信号处理\n const shutdown = async () => {\n console.log('\\n[yiyan-browser-agent] 正在关闭...');\n try { await agent.close(); } catch {}\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n if (parsed.command === 'login') {\n try {\n console.log('[yiyan-browser-agent] 启动登录流程...');\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.error('[yiyan-browser-agent] ✗ 登录失败:', errorMessage);\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 === 'debug') {\n try {\n console.log('[yiyan-browser-agent] 启动调试模式...');\n await agent.debug();\n console.log(formatCliOutput({\n success: true,\n question: 'debug',\n answer: 'Debug session completed',\n duration: 0,\n }));\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error('[yiyan-browser-agent] ✗ 调试失败:', errorMessage);\n console.log(formatCliOutput({\n success: false,\n question: 'debug',\n error: errorMessage,\n duration: 0,\n }));\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\nrunCli(process.argv.slice(2)).catch(err => {\n console.error('[yiyan-browser-agent] Uncaught error:', err);\n process.exit(1);\n});","// 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 dumpDebugInfo,\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 private _context: any = null; // 保存当前 context 以便关闭\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 const fs = require('fs');\n fs.mkdirSync(this.sessionDir, { recursive: true });\n }\n\n /**\n * 关闭浏览器(如果正在运行)\n */\n async close(): Promise<void> {\n if (this._context) {\n try {\n await this._context.close();\n } catch {}\n this._context = null;\n }\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-browser-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-browser-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-browser-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-browser-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 /**\n * Debug 模式:启动浏览器并输出 DOM 信息\n */\n async debug(): Promise<void> {\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: this.options.timeout,\n verbose: true,\n });\n\n try {\n await navigateToYiyan(page, true);\n await page.waitForTimeout(3000);\n await dumpDebugInfo(page);\n\n // 保持浏览器打开,让用户手动测试\n process.stderr.write('\\n[yiyan-browser-agent] 浏览器保持打开,可手动测试。\\n');\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器窗口结束 debug 模式...\\n');\n\n // 等待浏览器关闭\n await new Promise<void>((resolve) => {\n context.on('close', () => resolve());\n });\n } finally {\n // 浏览器已由用户关闭,这里只是清理\n try {\n await context.close();\n } catch {}\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 (文心一言)\n// 参考 deepseek-browser-agent 的实现方式\nimport { chromium, Page, BrowserContext, ElementHandle } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 选择器配置 — 多 fallback 策略,不依赖单一选择器\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SELECTORS = {\n // 输入框选择器(按优先级排序)\n chatInput: [\n '#chat-input',\n 'textarea[placeholder*=\"输入\"]',\n 'textarea[placeholder]',\n 'textarea',\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n ],\n\n // 发送按钮选择器\n sendButton: [\n 'button[aria-label*=\"发送\"]',\n 'button[aria-label*=\"Send\"]',\n '[data-testid=\"send-button\"]',\n 'button[type=\"submit\"]',\n '[class*=\"send-btn\"]',\n '[class*=\"sendBtn\"]',\n '[class*=\"send-button\"]',\n ],\n\n // 响应容器选择器\n responseContainer: [\n '[class*=\"answerBox\"]',\n '[class*=\"response\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"assistant\"]',\n '[class*=\"markdown\"]',\n '[class*=\"message-content\"]',\n '[class*=\"chat-message\"]',\n ],\n\n // 停止生成按钮\n stopButton: [\n 'button[aria-label*=\"停止\"]',\n 'button[aria-label*=\"Stop\"]',\n '[class*=\"stop-btn\"]',\n '[class*=\"stopBtn\"]',\n '[class*=\"stop-gen\"]',\n ],\n};\n\n/** 日志输出 */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-browser-agent] ${msg}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 启动浏览器\n// ─────────────────────────────────────────────────────────────────────────────\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 // 始终输出启动日志(便于排查问题)\n process.stderr.write('[yiyan-browser-agent] 启动 Chromium 浏览器...\\n');\n\n try {\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\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 context.setDefaultTimeout(timeout);\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 process.stderr.write('[yiyan-browser-agent] 浏览器启动完成\\n');\n return { context, page };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[yiyan-browser-agent] ✗ 浏览器启动失败: ${errorMsg}\\n`);\n process.stderr.write('[yiyan-browser-agent] 提示: Ubuntu 需要先运行: npx playwright install-deps chromium\\n');\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${errorMsg}`\n );\n }\n}\n\nexport async function closeBrowser(context: BrowserContext, verbose?: boolean): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器...\\n');\n try {\n await context.close();\n process.stderr.write('[yiyan-browser-agent] 浏览器已关闭\\n');\n } catch {}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 导航\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 导航到文心一言...\\n');\n try {\n await page.goto(YIYAN_CHAT_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });\n await page.waitForTimeout(1500);\n process.stderr.write('[yiyan-browser-agent] 页面加载完成\\n');\n } catch (err) {\n process.stderr.write(`[yiyan-browser-agent] 导航警告: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 登录检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n await page.waitForTimeout(2000);\n\n const isLoggedIn = await page.evaluate(() => {\n const url = window.location.href;\n const bodyText = document.body?.innerText || '';\n\n // URL 包含登录相关路径\n if (url.includes('/auth') || url.includes('/login') || url.includes('/sign')) return false;\n\n // 页面包含登录相关文字\n if (bodyText.includes('未登录') || bodyText.includes('请登录')) return false;\n\n // 存在登录按钮\n if (document.querySelector('input[type=\"password\"]')) return false;\n\n const loginBtn = document.querySelector('button');\n if (loginBtn && loginBtn.textContent?.trim() === '登录') return false;\n\n return true;\n });\n\n process.stderr.write(isLoggedIn ? '[yiyan-browser-agent] ✓ 已检测到登录状态\\n' : '[yiyan-browser-agent] ⚠ 未登录\\n');\n return isLoggedIn;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 验证码检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const hasCaptcha = await page.evaluate(() => {\n const bodyText = document.body.innerText || '';\n const indicators = ['验证码', '请完成验证', '安全验证', '滑动验证', 'captcha'];\n for (const kw of indicators) {\n if (bodyText.includes(kw)) return true;\n }\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n return dialogs.length > 0;\n });\n\n if (hasCaptcha) log(verbose, '⚠ 检测到验证码!');\n return hasCaptcha;\n}\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 messages = {\n captcha: '检测到验证码,请在浏览器中手动完成验证',\n login: '检测到未登录,请在浏览器中手动登录',\n 'no-reply': 'AI 未回复,请检查浏览器是否需要手动操作',\n };\n\n process.stderr.write(`\\n[yiyan-browser-agent] ⚠ ${messages[reason]}\\n`);\n process.stderr.write('[yiyan-browser-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n const maxWait = 180000;\n const start = Date.now();\n\n while (Date.now() - start < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha' && !await checkCaptcha(page, false)) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n if (reason === 'login' && await checkLoggedIn(page, false)) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n if (reason === 'no-reply' && await getMessageCount(page) > 0) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 发送消息 — 参考 deepseek-browser-agent 的实现\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function sendMessage(\n page: Page,\n message: string,\n verbose = false,\n headful = false\n): Promise<void> {\n // 查找输入框\n const input = await findInput(page, verbose);\n if (!input) {\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击获取焦点\n await input.click({ force: true });\n await page.waitForTimeout(200);\n\n // 清除现有内容\n await page.keyboard.press('Control+a');\n await page.waitForTimeout(100);\n\n // 输入内容 — 使用 execCommand(contenteditable 最可靠方式)\n const isTextarea = await input.evaluate(el => el.tagName.toLowerCase() === 'textarea');\n\n if (isTextarea) {\n // textarea 使用 fill\n await input.fill(message);\n } else {\n // contenteditable 使用 execCommand\n await input.evaluate((el, content) => {\n el.focus();\n document.execCommand('selectAll', false, null);\n document.execCommand('delete', false, null);\n document.execCommand('insertText', false, content);\n el.dispatchEvent(new InputEvent('input', { bubbles: true, data: content }));\n }, message);\n }\n\n await page.waitForTimeout(400);\n log(verbose, `已输入问题: \"${message.substring(0, 50)}...\"`);\n\n // 尝试点击发送按钮,失败则按 Enter\n const sent = await clickSendButton(page);\n if (!sent) {\n await page.keyboard.press('Enter');\n }\n\n await page.waitForTimeout(500);\n\n // 检查验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected. Use --headful to solve it.');\n }\n }\n}\n\nasync function findInput(page: Page, verbose = false): Promise<ElementHandle | null> {\n for (const sel of SELECTORS.chatInput) {\n try {\n const el = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (el) {\n log(verbose, `✓ 输入框: ${sel}`);\n return el;\n }\n } catch {}\n }\n return null;\n}\n\nasync function clickSendButton(page: Page): Promise<boolean> {\n for (const sel of SELECTORS.sendButton) {\n try {\n const el = await page.$(sel);\n if (el && await el.isVisible() && await el.isEnabled()) {\n await el.click();\n return true;\n }\n } catch {}\n }\n return false;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 等待回复 — 参考 deepseek-browser-agent 的稳定检测策略\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, 120000);\n const stableDelay = 2500; // 文本稳定 2.5 秒视为完成\n const start = Date.now();\n\n // Phase 1: 等待新消息出现\n const initialCount = await getMessageCount(page);\n let appeared = false;\n\n while (Date.now() - start < 12000) {\n const count = await getMessageCount(page);\n if (count > initialCount) {\n appeared = true;\n log(verbose, '✓ AI 回复已开始生成');\n break;\n }\n await page.waitForTimeout(400);\n }\n\n if (!appeared) {\n log(verbose, '回复可能延迟,继续等待...');\n }\n\n // Phase 2: 等待文本稳定\n let lastText = '';\n let stableStart: number | null = null;\n\n while (Date.now() - start < maxWait) {\n const text = await extractLastMessage(page);\n\n if (text !== lastText) {\n lastText = text;\n stableStart = null;\n } else if (text.length > 0) {\n if (!stableStart) stableStart = Date.now();\n else if (Date.now() - stableStart >= stableDelay) {\n if (!await isGenerating(page)) {\n log(verbose, `✓ AI 回复已完成(${text.length}字)`);\n break;\n }\n stableStart = null;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n // 检查失败情况\n if (lastText.length === 0) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected.');\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError('TIMEOUT', 'AI reply timeout.');\n }\n }\n\n await page.waitForTimeout(1000);\n}\n\nasync function getMessageCount(page: Page): Promise<number> {\n return await page.evaluate(() => {\n for (const sel of [\n '[class*=\"answerBox\"]',\n '[class*=\"assistant\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"response\"]',\n ]) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) return els.length;\n }\n return document.querySelectorAll('[class*=\"message\"]').length;\n });\n}\n\nasync function isGenerating(page: Page): Promise<boolean> {\n return await page.evaluate(() => {\n // 检查停止按钮\n for (const sel of ['button[aria-label*=\"停止\"]', '[class*=\"stop\"]', '[class*=\"generating\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n // 检查加载指示器\n for (const sel of ['[class*=\"loading\"]', '[class*=\"typing\"]', '[class*=\"spinner\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n return false;\n });\n}\n\nasync function extractLastMessage(page: Page): Promise<string> {\n return await page.evaluate(() => {\n function getFullText(el: Element): string {\n if (!el) return '';\n let result = '';\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n result += node.textContent || '';\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const tag = (node as Element).tagName.toLowerCase();\n\n if (tag === 'pre') {\n const codeEl = node.querySelector('code');\n if (codeEl) {\n const cls = codeEl.className || '';\n const lang = (cls.match(/language-(\\S+)/) || [])[1] || '';\n result += '\\n```' + lang + '\\n' + (codeEl.textContent || '') + '\\n```\\n';\n } else {\n result += '\\n```\\n' + (node.textContent || '') + '\\n```\\n';\n }\n return;\n }\n\n for (const child of node.childNodes) walk(child);\n\n if (['p', 'div', 'li', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {\n result += '\\n';\n }\n }\n\n walk(el);\n return result.trim();\n }\n\n // 尝试多个选择器\n for (const sel of SELECTORS.responseContainer) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) {\n const text = getFullText(els[els.length - 1]);\n if (text.length > 10) return text;\n }\n }\n\n // 备选:markdown 容器\n const mdEls = document.querySelectorAll('[class*=\"markdown\"], [class*=\"prose\"]');\n if (mdEls.length > 0) {\n const text = getFullText(mdEls[mdEls.length - 1]);\n if (text.length > 10) return text;\n }\n\n return '';\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 提取回复(简化版)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复...');\n\n const text = await extractLastMessage(page);\n\n if (text.length > 0) {\n const cleaned = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\n log(verbose, `提取成功: ${cleaned.length} 字符`);\n return cleaned;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 调试工具\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function dumpDebugInfo(page: Page): Promise<void> {\n const info = await page.evaluate(() => {\n const classFreq: Record<string, number> = {};\n document.querySelectorAll('*').forEach(el => {\n el.classList.forEach(c => {\n if (c.match(/message|chat|input|send|stop|markdown|content|assistant|user|bot|answer/i)) {\n classFreq[c] = (classFreq[c] || 0) + 1;\n }\n });\n });\n\n const inputs = Array.from(document.querySelectorAll('textarea, [contenteditable]')).map(e => ({\n tag: e.tagName,\n id: e.id || null,\n class: (e.className?.toString() || '').substring(0, 80),\n placeholder: (e as any).placeholder || null,\n editable: e.isContentEditable,\n visible: e.offsetParent !== null,\n }));\n\n return {\n url: window.location.href,\n title: document.title,\n classes: Object.entries(classFreq).sort((a, b) => b[1] - a[1]).slice(0, 40),\n inputs,\n };\n });\n\n console.log('\\n' + '═'.repeat(60));\n console.log(' DOM DEBUG INFO');\n console.log('═'.repeat(60));\n console.log('URL :', info.url);\n console.log('Title :', info.title);\n console.log('\\nInput elements:');\n info.inputs.forEach(i => console.log(' ', JSON.stringify(i)));\n console.log('\\nMatching CSS classes (by frequency):');\n info.classes.forEach(([cls, count]) => console.log(` ${String(count).padStart(3)}x .${cls}`));\n console.log('═'.repeat(60) + '\\n');\n}"],"mappings":"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","names":["fs","path","os","fs"]}
package/dist/index.d.ts CHANGED
@@ -1,40 +1,5 @@
1
- /**
2
- * yiyan-browser-agent 类型定义
3
- */
4
- /** 配置选项 */
5
- interface YiyanAgentOptions {
6
- /** 超时毫秒,默认 120000 */
7
- timeout?: number;
8
- /** 重试次数,默认 3 */
9
- retryCount?: number;
10
- /** 自定义 profile 目录 */
11
- profileDir?: string;
12
- /** 自定义 Chrome 可执行文件路径 */
13
- chromePath?: string;
14
- }
15
- /** CLI 输出格式 */
16
- interface CliOutput {
17
- success: boolean;
18
- /** 用户发送的问题 */
19
- question: string;
20
- /** 成功时有值 */
21
- answer?: string;
22
- /** 失败时有值 */
23
- error?: string;
24
- /** 耗时毫秒 */
25
- duration: number;
26
- }
27
- /** 错误类型 */
28
- type YiyanAgentErrorType = 'BROWSER_LAUNCH' | 'PROFILE_COPY' | 'TIMEOUT' | 'NETWORK' | 'CAPTCHA';
29
- /** 自定义错误类 */
30
- declare class YiyanAgentError extends Error {
31
- type: YiyanAgentErrorType;
32
- constructor(type: YiyanAgentErrorType, message: string);
33
- }
34
- /** 默认配置 */
35
- declare const DEFAULT_OPTIONS: Required<YiyanAgentOptions>;
36
- /** 文心一言网页 URL */
37
- declare const YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
1
+ import { c as YiyanAgentOptions } from './types-BhQ78DYf.js';
2
+ export { C as CliOutput, D as DEFAULT_OPTIONS, Y as YIYAN_CHAT_URL, a as YiyanAgentError, b as YiyanAgentErrorType } from './types-BhQ78DYf.js';
38
3
 
39
4
  /**
40
5
  * 文心一言浏览器代理
@@ -105,4 +70,4 @@ declare function readConfig(): YiyanConfig;
105
70
  */
106
71
  declare function saveConfig(config: YiyanConfig): void;
107
72
 
108
- export { CONFIG_FILE_PATH, type CliOutput, DEFAULT_OPTIONS, DEFAULT_SESSION_DIR, YIYAN_CHAT_URL, YiyanAgent, YiyanAgentError, type YiyanAgentErrorType, type YiyanAgentOptions, type YiyanConfig, readConfig, saveConfig };
73
+ export { CONFIG_FILE_PATH, DEFAULT_SESSION_DIR, YiyanAgent, YiyanAgentOptions, type YiyanConfig, readConfig, saveConfig };
package/dist/index.js CHANGED
@@ -1,13 +1,49 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ CONFIG_FILE_PATH: () => CONFIG_FILE_PATH,
34
+ DEFAULT_OPTIONS: () => DEFAULT_OPTIONS,
35
+ DEFAULT_SESSION_DIR: () => DEFAULT_SESSION_DIR2,
36
+ YIYAN_CHAT_URL: () => YIYAN_CHAT_URL,
37
+ YiyanAgent: () => YiyanAgent,
38
+ YiyanAgentError: () => YiyanAgentError,
39
+ readConfig: () => readConfig,
40
+ saveConfig: () => saveConfig
6
41
  });
42
+ module.exports = __toCommonJS(src_exports);
7
43
 
8
44
  // src/agent.ts
9
- import path from "path";
10
- import os from "os";
45
+ var import_path = __toESM(require("path"));
46
+ var import_os = __toESM(require("os"));
11
47
 
12
48
  // src/types.ts
13
49
  var YiyanAgentError = class extends Error {
@@ -27,8 +63,8 @@ var DEFAULT_OPTIONS = {
27
63
  var YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
28
64
 
29
65
  // src/browser.ts
30
- import { chromium } from "playwright";
31
- import fs from "fs";
66
+ var import_playwright = require("playwright");
67
+ var import_fs = __toESM(require("fs"));
32
68
  var SELECTORS = {
33
69
  // 输入框选择器(按优先级排序)
34
70
  chatInput: [
@@ -78,10 +114,10 @@ async function launchBrowser(options) {
78
114
  const { sessionDir, headless, timeout = 3e4, verbose = false } = options;
79
115
  process.stderr.write("[yiyan-browser-agent] \u542F\u52A8 Chromium \u6D4F\u89C8\u5668...\n");
80
116
  try {
81
- if (!fs.existsSync(sessionDir)) {
82
- fs.mkdirSync(sessionDir, { recursive: true });
117
+ if (!import_fs.default.existsSync(sessionDir)) {
118
+ import_fs.default.mkdirSync(sessionDir, { recursive: true });
83
119
  }
84
- const context = await chromium.launchPersistentContext(sessionDir, {
120
+ const context = await import_playwright.chromium.launchPersistentContext(sessionDir, {
85
121
  headless,
86
122
  viewport: { width: 1280, height: 900 },
87
123
  userAgent: [
@@ -435,7 +471,7 @@ async function dumpDebugInfo(page) {
435
471
  }
436
472
 
437
473
  // src/agent.ts
438
- var DEFAULT_SESSION_DIR = path.join(os.homedir(), ".yiyan-browser-agent", "session");
474
+ var DEFAULT_SESSION_DIR = import_path.default.join(import_os.default.homedir(), ".yiyan-browser-agent", "session");
439
475
  var YiyanAgent = class {
440
476
  options;
441
477
  sessionDir;
@@ -449,7 +485,7 @@ var YiyanAgent = class {
449
485
  };
450
486
  this.sessionDir = this.options.profileDir || DEFAULT_SESSION_DIR;
451
487
  this.verbose = options?.verbose ?? false;
452
- const fs3 = __require("fs");
488
+ const fs3 = require("fs");
453
489
  fs3.mkdirSync(this.sessionDir, { recursive: true });
454
490
  }
455
491
  /**
@@ -559,7 +595,7 @@ var YiyanAgent = class {
559
595
  * 检查状态
560
596
  */
561
597
  status() {
562
- const fs3 = __require("fs");
598
+ const fs3 = require("fs");
563
599
  return {
564
600
  loggedIn: fs3.existsSync(this.sessionDir),
565
601
  sessionPath: this.sessionDir
@@ -594,15 +630,15 @@ var YiyanAgent = class {
594
630
  };
595
631
 
596
632
  // src/profile.ts
597
- import path2 from "path";
598
- import os2 from "os";
599
- import fs2 from "fs";
600
- var CONFIG_FILE_PATH = path2.join(os2.homedir(), ".yiyan-browser-agent", "config.json");
601
- var DEFAULT_SESSION_DIR2 = path2.join(os2.homedir(), ".yiyan-browser-agent", "session");
633
+ var import_path2 = __toESM(require("path"));
634
+ var import_os2 = __toESM(require("os"));
635
+ var import_fs2 = __toESM(require("fs"));
636
+ var CONFIG_FILE_PATH = import_path2.default.join(import_os2.default.homedir(), ".yiyan-browser-agent", "config.json");
637
+ var DEFAULT_SESSION_DIR2 = import_path2.default.join(import_os2.default.homedir(), ".yiyan-browser-agent", "session");
602
638
  function readConfig() {
603
639
  try {
604
- if (fs2.existsSync(CONFIG_FILE_PATH)) {
605
- const content = fs2.readFileSync(CONFIG_FILE_PATH, "utf-8");
640
+ if (import_fs2.default.existsSync(CONFIG_FILE_PATH)) {
641
+ const content = import_fs2.default.readFileSync(CONFIG_FILE_PATH, "utf-8");
606
642
  return JSON.parse(content);
607
643
  }
608
644
  } catch {
@@ -610,20 +646,21 @@ function readConfig() {
610
646
  return {};
611
647
  }
612
648
  function saveConfig(config) {
613
- const configDir = path2.dirname(CONFIG_FILE_PATH);
614
- if (!fs2.existsSync(configDir)) {
615
- fs2.mkdirSync(configDir, { recursive: true });
649
+ const configDir = import_path2.default.dirname(CONFIG_FILE_PATH);
650
+ if (!import_fs2.default.existsSync(configDir)) {
651
+ import_fs2.default.mkdirSync(configDir, { recursive: true });
616
652
  }
617
- fs2.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2));
653
+ import_fs2.default.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2));
618
654
  }
619
- export {
655
+ // Annotate the CommonJS export names for ESM import in node:
656
+ 0 && (module.exports = {
620
657
  CONFIG_FILE_PATH,
621
658
  DEFAULT_OPTIONS,
622
- DEFAULT_SESSION_DIR2 as DEFAULT_SESSION_DIR,
659
+ DEFAULT_SESSION_DIR,
623
660
  YIYAN_CHAT_URL,
624
661
  YiyanAgent,
625
662
  YiyanAgentError,
626
663
  readConfig,
627
664
  saveConfig
628
- };
665
+ });
629
666
  //# sourceMappingURL=index.js.map
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 dumpDebugInfo,\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 private _context: any = null; // 保存当前 context 以便关闭\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 const fs = require('fs');\n fs.mkdirSync(this.sessionDir, { recursive: true });\n }\n\n /**\n * 关闭浏览器(如果正在运行)\n */\n async close(): Promise<void> {\n if (this._context) {\n try {\n await this._context.close();\n } catch {}\n this._context = null;\n }\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-browser-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-browser-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-browser-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-browser-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 /**\n * Debug 模式:启动浏览器并输出 DOM 信息\n */\n async debug(): Promise<void> {\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: this.options.timeout,\n verbose: true,\n });\n\n try {\n await navigateToYiyan(page, true);\n await page.waitForTimeout(3000);\n await dumpDebugInfo(page);\n\n // 保持浏览器打开,让用户手动测试\n process.stderr.write('\\n[yiyan-browser-agent] 浏览器保持打开,可手动测试。\\n');\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器窗口结束 debug 模式...\\n');\n\n // 等待浏览器关闭\n await new Promise<void>((resolve) => {\n context.on('close', () => resolve());\n });\n } finally {\n // 浏览器已由用户关闭,这里只是清理\n try {\n await context.close();\n } catch {}\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 (文心一言)\n// 参考 deepseek-browser-agent 的实现方式\nimport { chromium, Page, BrowserContext, ElementHandle } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 选择器配置 — 多 fallback 策略,不依赖单一选择器\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SELECTORS = {\n // 输入框选择器(按优先级排序)\n chatInput: [\n '#chat-input',\n 'textarea[placeholder*=\"输入\"]',\n 'textarea[placeholder]',\n 'textarea',\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n ],\n\n // 发送按钮选择器\n sendButton: [\n 'button[aria-label*=\"发送\"]',\n 'button[aria-label*=\"Send\"]',\n '[data-testid=\"send-button\"]',\n 'button[type=\"submit\"]',\n '[class*=\"send-btn\"]',\n '[class*=\"sendBtn\"]',\n '[class*=\"send-button\"]',\n ],\n\n // 响应容器选择器\n responseContainer: [\n '[class*=\"answerBox\"]',\n '[class*=\"response\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"assistant\"]',\n '[class*=\"markdown\"]',\n '[class*=\"message-content\"]',\n '[class*=\"chat-message\"]',\n ],\n\n // 停止生成按钮\n stopButton: [\n 'button[aria-label*=\"停止\"]',\n 'button[aria-label*=\"Stop\"]',\n '[class*=\"stop-btn\"]',\n '[class*=\"stopBtn\"]',\n '[class*=\"stop-gen\"]',\n ],\n};\n\n/** 日志输出 */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-browser-agent] ${msg}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 启动浏览器\n// ─────────────────────────────────────────────────────────────────────────────\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 // 始终输出启动日志(便于排查问题)\n process.stderr.write('[yiyan-browser-agent] 启动 Chromium 浏览器...\\n');\n\n try {\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\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 context.setDefaultTimeout(timeout);\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 process.stderr.write('[yiyan-browser-agent] 浏览器启动完成\\n');\n return { context, page };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[yiyan-browser-agent] ✗ 浏览器启动失败: ${errorMsg}\\n`);\n process.stderr.write('[yiyan-browser-agent] 提示: Ubuntu 需要先运行: npx playwright install-deps chromium\\n');\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${errorMsg}`\n );\n }\n}\n\nexport async function closeBrowser(context: BrowserContext, verbose?: boolean): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器...\\n');\n try {\n await context.close();\n process.stderr.write('[yiyan-browser-agent] 浏览器已关闭\\n');\n } catch {}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 导航\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 导航到文心一言...\\n');\n try {\n await page.goto(YIYAN_CHAT_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });\n await page.waitForTimeout(1500);\n process.stderr.write('[yiyan-browser-agent] 页面加载完成\\n');\n } catch (err) {\n process.stderr.write(`[yiyan-browser-agent] 导航警告: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 登录检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n await page.waitForTimeout(2000);\n\n const isLoggedIn = await page.evaluate(() => {\n const url = window.location.href;\n const bodyText = document.body?.innerText || '';\n\n // URL 包含登录相关路径\n if (url.includes('/auth') || url.includes('/login') || url.includes('/sign')) return false;\n\n // 页面包含登录相关文字\n if (bodyText.includes('未登录') || bodyText.includes('请登录')) return false;\n\n // 存在登录按钮\n if (document.querySelector('input[type=\"password\"]')) return false;\n\n const loginBtn = document.querySelector('button');\n if (loginBtn && loginBtn.textContent?.trim() === '登录') return false;\n\n return true;\n });\n\n process.stderr.write(isLoggedIn ? '[yiyan-browser-agent] ✓ 已检测到登录状态\\n' : '[yiyan-browser-agent] ⚠ 未登录\\n');\n return isLoggedIn;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 验证码检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const hasCaptcha = await page.evaluate(() => {\n const bodyText = document.body.innerText || '';\n const indicators = ['验证码', '请完成验证', '安全验证', '滑动验证', 'captcha'];\n for (const kw of indicators) {\n if (bodyText.includes(kw)) return true;\n }\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n return dialogs.length > 0;\n });\n\n if (hasCaptcha) log(verbose, '⚠ 检测到验证码!');\n return hasCaptcha;\n}\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 messages = {\n captcha: '检测到验证码,请在浏览器中手动完成验证',\n login: '检测到未登录,请在浏览器中手动登录',\n 'no-reply': 'AI 未回复,请检查浏览器是否需要手动操作',\n };\n\n process.stderr.write(`\\n[yiyan-browser-agent] ⚠ ${messages[reason]}\\n`);\n process.stderr.write('[yiyan-browser-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n const maxWait = 180000;\n const start = Date.now();\n\n while (Date.now() - start < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha' && !await checkCaptcha(page, false)) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n if (reason === 'login' && await checkLoggedIn(page, false)) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n if (reason === 'no-reply' && await getMessageCount(page) > 0) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 发送消息 — 参考 deepseek-browser-agent 的实现\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function sendMessage(\n page: Page,\n message: string,\n verbose = false,\n headful = false\n): Promise<void> {\n // 查找输入框\n const input = await findInput(page, verbose);\n if (!input) {\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击获取焦点\n await input.click({ force: true });\n await page.waitForTimeout(200);\n\n // 清除现有内容\n await page.keyboard.press('Control+a');\n await page.waitForTimeout(100);\n\n // 输入内容 — 使用 execCommand(contenteditable 最可靠方式)\n const isTextarea = await input.evaluate(el => el.tagName.toLowerCase() === 'textarea');\n\n if (isTextarea) {\n // textarea 使用 fill\n await input.fill(message);\n } else {\n // contenteditable 使用 execCommand\n await input.evaluate((el, content) => {\n el.focus();\n document.execCommand('selectAll', false, null);\n document.execCommand('delete', false, null);\n document.execCommand('insertText', false, content);\n el.dispatchEvent(new InputEvent('input', { bubbles: true, data: content }));\n }, message);\n }\n\n await page.waitForTimeout(400);\n log(verbose, `已输入问题: \"${message.substring(0, 50)}...\"`);\n\n // 尝试点击发送按钮,失败则按 Enter\n const sent = await clickSendButton(page);\n if (!sent) {\n await page.keyboard.press('Enter');\n }\n\n await page.waitForTimeout(500);\n\n // 检查验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected. Use --headful to solve it.');\n }\n }\n}\n\nasync function findInput(page: Page, verbose = false): Promise<ElementHandle | null> {\n for (const sel of SELECTORS.chatInput) {\n try {\n const el = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (el) {\n log(verbose, `✓ 输入框: ${sel}`);\n return el;\n }\n } catch {}\n }\n return null;\n}\n\nasync function clickSendButton(page: Page): Promise<boolean> {\n for (const sel of SELECTORS.sendButton) {\n try {\n const el = await page.$(sel);\n if (el && await el.isVisible() && await el.isEnabled()) {\n await el.click();\n return true;\n }\n } catch {}\n }\n return false;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 等待回复 — 参考 deepseek-browser-agent 的稳定检测策略\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, 120000);\n const stableDelay = 2500; // 文本稳定 2.5 秒视为完成\n const start = Date.now();\n\n // Phase 1: 等待新消息出现\n const initialCount = await getMessageCount(page);\n let appeared = false;\n\n while (Date.now() - start < 12000) {\n const count = await getMessageCount(page);\n if (count > initialCount) {\n appeared = true;\n log(verbose, '✓ AI 回复已开始生成');\n break;\n }\n await page.waitForTimeout(400);\n }\n\n if (!appeared) {\n log(verbose, '回复可能延迟,继续等待...');\n }\n\n // Phase 2: 等待文本稳定\n let lastText = '';\n let stableStart: number | null = null;\n\n while (Date.now() - start < maxWait) {\n const text = await extractLastMessage(page);\n\n if (text !== lastText) {\n lastText = text;\n stableStart = null;\n } else if (text.length > 0) {\n if (!stableStart) stableStart = Date.now();\n else if (Date.now() - stableStart >= stableDelay) {\n if (!await isGenerating(page)) {\n log(verbose, `✓ AI 回复已完成(${text.length}字)`);\n break;\n }\n stableStart = null;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n // 检查失败情况\n if (lastText.length === 0) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected.');\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError('TIMEOUT', 'AI reply timeout.');\n }\n }\n\n await page.waitForTimeout(1000);\n}\n\nasync function getMessageCount(page: Page): Promise<number> {\n return await page.evaluate(() => {\n for (const sel of [\n '[class*=\"answerBox\"]',\n '[class*=\"assistant\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"response\"]',\n ]) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) return els.length;\n }\n return document.querySelectorAll('[class*=\"message\"]').length;\n });\n}\n\nasync function isGenerating(page: Page): Promise<boolean> {\n return await page.evaluate(() => {\n // 检查停止按钮\n for (const sel of ['button[aria-label*=\"停止\"]', '[class*=\"stop\"]', '[class*=\"generating\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n // 检查加载指示器\n for (const sel of ['[class*=\"loading\"]', '[class*=\"typing\"]', '[class*=\"spinner\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n return false;\n });\n}\n\nasync function extractLastMessage(page: Page): Promise<string> {\n return await page.evaluate(() => {\n function getFullText(el: Element): string {\n if (!el) return '';\n let result = '';\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n result += node.textContent || '';\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const tag = (node as Element).tagName.toLowerCase();\n\n if (tag === 'pre') {\n const codeEl = node.querySelector('code');\n if (codeEl) {\n const cls = codeEl.className || '';\n const lang = (cls.match(/language-(\\S+)/) || [])[1] || '';\n result += '\\n```' + lang + '\\n' + (codeEl.textContent || '') + '\\n```\\n';\n } else {\n result += '\\n```\\n' + (node.textContent || '') + '\\n```\\n';\n }\n return;\n }\n\n for (const child of node.childNodes) walk(child);\n\n if (['p', 'div', 'li', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {\n result += '\\n';\n }\n }\n\n walk(el);\n return result.trim();\n }\n\n // 尝试多个选择器\n for (const sel of SELECTORS.responseContainer) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) {\n const text = getFullText(els[els.length - 1]);\n if (text.length > 10) return text;\n }\n }\n\n // 备选:markdown 容器\n const mdEls = document.querySelectorAll('[class*=\"markdown\"], [class*=\"prose\"]');\n if (mdEls.length > 0) {\n const text = getFullText(mdEls[mdEls.length - 1]);\n if (text.length > 10) return text;\n }\n\n return '';\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 提取回复(简化版)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复...');\n\n const text = await extractLastMessage(page);\n\n if (text.length > 0) {\n const cleaned = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\n log(verbose, `提取成功: ${cleaned.length} 字符`);\n return cleaned;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 调试工具\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function dumpDebugInfo(page: Page): Promise<void> {\n const info = await page.evaluate(() => {\n const classFreq: Record<string, number> = {};\n document.querySelectorAll('*').forEach(el => {\n el.classList.forEach(c => {\n if (c.match(/message|chat|input|send|stop|markdown|content|assistant|user|bot|answer/i)) {\n classFreq[c] = (classFreq[c] || 0) + 1;\n }\n });\n });\n\n const inputs = Array.from(document.querySelectorAll('textarea, [contenteditable]')).map(e => ({\n tag: e.tagName,\n id: e.id || null,\n class: (e.className?.toString() || '').substring(0, 80),\n placeholder: (e as any).placeholder || null,\n editable: e.isContentEditable,\n visible: e.offsetParent !== null,\n }));\n\n return {\n url: window.location.href,\n title: document.title,\n classes: Object.entries(classFreq).sort((a, b) => b[1] - a[1]).slice(0, 40),\n inputs,\n };\n });\n\n console.log('\\n' + '═'.repeat(60));\n console.log(' DOM DEBUG INFO');\n console.log('═'.repeat(60));\n console.log('URL :', info.url);\n console.log('Title :', info.title);\n console.log('\\nInput elements:');\n info.inputs.forEach(i => console.log(' ', JSON.stringify(i)));\n console.log('\\nMatching CSS classes (by frequency):');\n info.classes.forEach(([cls, count]) => console.log(` ${String(count).padStart(3)}x .${cls}`));\n console.log('═'.repeat(60) + '\\n');\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"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/types.ts","../src/browser.ts","../src/profile.ts"],"sourcesContent":["export { YiyanAgent } from './agent';\nexport {\n YiyanAgentOptions,\n CliOutput,\n YiyanAgentError,\n YiyanAgentErrorType,\n DEFAULT_OPTIONS,\n YIYAN_CHAT_URL,\n} from './types';\nexport {\n YiyanConfig,\n readConfig,\n saveConfig,\n CONFIG_FILE_PATH,\n DEFAULT_SESSION_DIR,\n} from './profile';","// 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 dumpDebugInfo,\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 private _context: any = null; // 保存当前 context 以便关闭\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 const fs = require('fs');\n fs.mkdirSync(this.sessionDir, { recursive: true });\n }\n\n /**\n * 关闭浏览器(如果正在运行)\n */\n async close(): Promise<void> {\n if (this._context) {\n try {\n await this._context.close();\n } catch {}\n this._context = null;\n }\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-browser-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-browser-agent] ╔══════════════════════════════════════════════╗\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 🔐 LOGIN REQUIRED ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 1. Log in to Yiyan in the browser window ║\\n');\n process.stderr.write('[yiyan-browser-agent] ║ 2. Return here and press ENTER to continue ║\\n');\n process.stderr.write('[yiyan-browser-agent] ╚══════════════════════════════════════════════╝\\n\\n');\n\n // 等待用户按 Enter 确认\n await this.waitForEnter();\n\n process.stderr.write('[yiyan-browser-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 /**\n * Debug 模式:启动浏览器并输出 DOM 信息\n */\n async debug(): Promise<void> {\n const { context, page } = await launchBrowser({\n sessionDir: this.sessionDir,\n headless: false,\n timeout: this.options.timeout,\n verbose: true,\n });\n\n try {\n await navigateToYiyan(page, true);\n await page.waitForTimeout(3000);\n await dumpDebugInfo(page);\n\n // 保持浏览器打开,让用户手动测试\n process.stderr.write('\\n[yiyan-browser-agent] 浏览器保持打开,可手动测试。\\n');\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器窗口结束 debug 模式...\\n');\n\n // 等待浏览器关闭\n await new Promise<void>((resolve) => {\n context.on('close', () => resolve());\n });\n } finally {\n // 浏览器已由用户关闭,这里只是清理\n try {\n await context.close();\n } catch {}\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 (文心一言)\n// 参考 deepseek-browser-agent 的实现方式\nimport { chromium, Page, BrowserContext, ElementHandle } from 'playwright';\nimport { YiyanAgentError, YIYAN_CHAT_URL } from './types';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 选择器配置 — 多 fallback 策略,不依赖单一选择器\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SELECTORS = {\n // 输入框选择器(按优先级排序)\n chatInput: [\n '#chat-input',\n 'textarea[placeholder*=\"输入\"]',\n 'textarea[placeholder]',\n 'textarea',\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n ],\n\n // 发送按钮选择器\n sendButton: [\n 'button[aria-label*=\"发送\"]',\n 'button[aria-label*=\"Send\"]',\n '[data-testid=\"send-button\"]',\n 'button[type=\"submit\"]',\n '[class*=\"send-btn\"]',\n '[class*=\"sendBtn\"]',\n '[class*=\"send-button\"]',\n ],\n\n // 响应容器选择器\n responseContainer: [\n '[class*=\"answerBox\"]',\n '[class*=\"response\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"assistant\"]',\n '[class*=\"markdown\"]',\n '[class*=\"message-content\"]',\n '[class*=\"chat-message\"]',\n ],\n\n // 停止生成按钮\n stopButton: [\n 'button[aria-label*=\"停止\"]',\n 'button[aria-label*=\"Stop\"]',\n '[class*=\"stop-btn\"]',\n '[class*=\"stopBtn\"]',\n '[class*=\"stop-gen\"]',\n ],\n};\n\n/** 日志输出 */\nfunction log(verbose: boolean, msg: string): void {\n if (verbose) {\n process.stderr.write(`[yiyan-browser-agent] ${msg}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 启动浏览器\n// ─────────────────────────────────────────────────────────────────────────────\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 // 始终输出启动日志(便于排查问题)\n process.stderr.write('[yiyan-browser-agent] 启动 Chromium 浏览器...\\n');\n\n try {\n if (!fs.existsSync(sessionDir)) {\n fs.mkdirSync(sessionDir, { recursive: true });\n }\n\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 context.setDefaultTimeout(timeout);\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 process.stderr.write('[yiyan-browser-agent] 浏览器启动完成\\n');\n return { context, page };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[yiyan-browser-agent] ✗ 浏览器启动失败: ${errorMsg}\\n`);\n process.stderr.write('[yiyan-browser-agent] 提示: Ubuntu 需要先运行: npx playwright install-deps chromium\\n');\n throw new YiyanAgentError(\n 'BROWSER_LAUNCH',\n `Failed to launch browser: ${errorMsg}`\n );\n }\n}\n\nexport async function closeBrowser(context: BrowserContext, verbose?: boolean): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 关闭浏览器...\\n');\n try {\n await context.close();\n process.stderr.write('[yiyan-browser-agent] 浏览器已关闭\\n');\n } catch {}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 导航\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function navigateToYiyan(page: Page, verbose = false): Promise<void> {\n process.stderr.write('[yiyan-browser-agent] 导航到文心一言...\\n');\n try {\n await page.goto(YIYAN_CHAT_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });\n await page.waitForTimeout(1500);\n process.stderr.write('[yiyan-browser-agent] 页面加载完成\\n');\n } catch (err) {\n process.stderr.write(`[yiyan-browser-agent] 导航警告: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 登录检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkLoggedIn(page: Page, verbose = false): Promise<boolean> {\n await page.waitForTimeout(2000);\n\n const isLoggedIn = await page.evaluate(() => {\n const url = window.location.href;\n const bodyText = document.body?.innerText || '';\n\n // URL 包含登录相关路径\n if (url.includes('/auth') || url.includes('/login') || url.includes('/sign')) return false;\n\n // 页面包含登录相关文字\n if (bodyText.includes('未登录') || bodyText.includes('请登录')) return false;\n\n // 存在登录按钮\n if (document.querySelector('input[type=\"password\"]')) return false;\n\n const loginBtn = document.querySelector('button');\n if (loginBtn && loginBtn.textContent?.trim() === '登录') return false;\n\n return true;\n });\n\n process.stderr.write(isLoggedIn ? '[yiyan-browser-agent] ✓ 已检测到登录状态\\n' : '[yiyan-browser-agent] ⚠ 未登录\\n');\n return isLoggedIn;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 验证码检测\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function checkCaptcha(page: Page, verbose = false): Promise<boolean> {\n const hasCaptcha = await page.evaluate(() => {\n const bodyText = document.body.innerText || '';\n const indicators = ['验证码', '请完成验证', '安全验证', '滑动验证', 'captcha'];\n for (const kw of indicators) {\n if (bodyText.includes(kw)) return true;\n }\n const dialogs = document.querySelectorAll('[role=\"dialog\"], [class*=\"captcha\"], [class*=\"verify\"]');\n return dialogs.length > 0;\n });\n\n if (hasCaptcha) log(verbose, '⚠ 检测到验证码!');\n return hasCaptcha;\n}\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 messages = {\n captcha: '检测到验证码,请在浏览器中手动完成验证',\n login: '检测到未登录,请在浏览器中手动登录',\n 'no-reply': 'AI 未回复,请检查浏览器是否需要手动操作',\n };\n\n process.stderr.write(`\\n[yiyan-browser-agent] ⚠ ${messages[reason]}\\n`);\n process.stderr.write('[yiyan-browser-agent] 等待您操作完成...(操作完成后会自动继续)\\n\\n');\n\n const maxWait = 180000;\n const start = Date.now();\n\n while (Date.now() - start < maxWait) {\n await page.waitForTimeout(2000);\n\n if (reason === 'captcha' && !await checkCaptcha(page, false)) {\n log(verbose, '✓ 验证码已通过!');\n return;\n }\n if (reason === 'login' && await checkLoggedIn(page, false)) {\n log(verbose, '✓ 登录成功!');\n return;\n }\n if (reason === 'no-reply' && await getMessageCount(page) > 0) {\n log(verbose, '✓ AI 已开始回复!');\n return;\n }\n }\n\n log(verbose, '⚠ 等待用户操作超时(3分钟)');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 发送消息 — 参考 deepseek-browser-agent 的实现\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function sendMessage(\n page: Page,\n message: string,\n verbose = false,\n headful = false\n): Promise<void> {\n // 查找输入框\n const input = await findInput(page, verbose);\n if (!input) {\n throw new YiyanAgentError('NETWORK', 'Cannot find the Yiyan chat input box');\n }\n\n // 点击获取焦点\n await input.click({ force: true });\n await page.waitForTimeout(200);\n\n // 清除现有内容\n await page.keyboard.press('Control+a');\n await page.waitForTimeout(100);\n\n // 输入内容 — 使用 execCommand(contenteditable 最可靠方式)\n const isTextarea = await input.evaluate(el => el.tagName.toLowerCase() === 'textarea');\n\n if (isTextarea) {\n // textarea 使用 fill\n await input.fill(message);\n } else {\n // contenteditable 使用 execCommand\n await input.evaluate((el, content) => {\n el.focus();\n document.execCommand('selectAll', false, null);\n document.execCommand('delete', false, null);\n document.execCommand('insertText', false, content);\n el.dispatchEvent(new InputEvent('input', { bubbles: true, data: content }));\n }, message);\n }\n\n await page.waitForTimeout(400);\n log(verbose, `已输入问题: \"${message.substring(0, 50)}...\"`);\n\n // 尝试点击发送按钮,失败则按 Enter\n const sent = await clickSendButton(page);\n if (!sent) {\n await page.keyboard.press('Enter');\n }\n\n await page.waitForTimeout(500);\n\n // 检查验证码\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected. Use --headful to solve it.');\n }\n }\n}\n\nasync function findInput(page: Page, verbose = false): Promise<ElementHandle | null> {\n for (const sel of SELECTORS.chatInput) {\n try {\n const el = await page.waitForSelector(sel, { timeout: 4000, state: 'visible' });\n if (el) {\n log(verbose, `✓ 输入框: ${sel}`);\n return el;\n }\n } catch {}\n }\n return null;\n}\n\nasync function clickSendButton(page: Page): Promise<boolean> {\n for (const sel of SELECTORS.sendButton) {\n try {\n const el = await page.$(sel);\n if (el && await el.isVisible() && await el.isEnabled()) {\n await el.click();\n return true;\n }\n } catch {}\n }\n return false;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 等待回复 — 参考 deepseek-browser-agent 的稳定检测策略\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, 120000);\n const stableDelay = 2500; // 文本稳定 2.5 秒视为完成\n const start = Date.now();\n\n // Phase 1: 等待新消息出现\n const initialCount = await getMessageCount(page);\n let appeared = false;\n\n while (Date.now() - start < 12000) {\n const count = await getMessageCount(page);\n if (count > initialCount) {\n appeared = true;\n log(verbose, '✓ AI 回复已开始生成');\n break;\n }\n await page.waitForTimeout(400);\n }\n\n if (!appeared) {\n log(verbose, '回复可能延迟,继续等待...');\n }\n\n // Phase 2: 等待文本稳定\n let lastText = '';\n let stableStart: number | null = null;\n\n while (Date.now() - start < maxWait) {\n const text = await extractLastMessage(page);\n\n if (text !== lastText) {\n lastText = text;\n stableStart = null;\n } else if (text.length > 0) {\n if (!stableStart) stableStart = Date.now();\n else if (Date.now() - stableStart >= stableDelay) {\n if (!await isGenerating(page)) {\n log(verbose, `✓ AI 回复已完成(${text.length}字)`);\n break;\n }\n stableStart = null;\n }\n }\n\n await page.waitForTimeout(500);\n }\n\n // 检查失败情况\n if (lastText.length === 0) {\n if (await checkCaptcha(page, verbose)) {\n if (headful) {\n await waitForUserAction(page, 'captcha', verbose);\n } else {\n throw new YiyanAgentError('CAPTCHA', 'Captcha detected.');\n }\n } else if (headful) {\n await waitForUserAction(page, 'no-reply', verbose);\n } else {\n throw new YiyanAgentError('TIMEOUT', 'AI reply timeout.');\n }\n }\n\n await page.waitForTimeout(1000);\n}\n\nasync function getMessageCount(page: Page): Promise<number> {\n return await page.evaluate(() => {\n for (const sel of [\n '[class*=\"answerBox\"]',\n '[class*=\"assistant\"]',\n '[class*=\"ai-message\"]',\n '[class*=\"response\"]',\n ]) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) return els.length;\n }\n return document.querySelectorAll('[class*=\"message\"]').length;\n });\n}\n\nasync function isGenerating(page: Page): Promise<boolean> {\n return await page.evaluate(() => {\n // 检查停止按钮\n for (const sel of ['button[aria-label*=\"停止\"]', '[class*=\"stop\"]', '[class*=\"generating\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n // 检查加载指示器\n for (const sel of ['[class*=\"loading\"]', '[class*=\"typing\"]', '[class*=\"spinner\"]']) {\n const el = document.querySelector(sel);\n if (el) {\n const s = window.getComputedStyle(el);\n if (s.display !== 'none' && s.visibility !== 'hidden') return true;\n }\n }\n return false;\n });\n}\n\nasync function extractLastMessage(page: Page): Promise<string> {\n return await page.evaluate(() => {\n function getFullText(el: Element): string {\n if (!el) return '';\n let result = '';\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n result += node.textContent || '';\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const tag = (node as Element).tagName.toLowerCase();\n\n if (tag === 'pre') {\n const codeEl = node.querySelector('code');\n if (codeEl) {\n const cls = codeEl.className || '';\n const lang = (cls.match(/language-(\\S+)/) || [])[1] || '';\n result += '\\n```' + lang + '\\n' + (codeEl.textContent || '') + '\\n```\\n';\n } else {\n result += '\\n```\\n' + (node.textContent || '') + '\\n```\\n';\n }\n return;\n }\n\n for (const child of node.childNodes) walk(child);\n\n if (['p', 'div', 'li', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {\n result += '\\n';\n }\n }\n\n walk(el);\n return result.trim();\n }\n\n // 尝试多个选择器\n for (const sel of SELECTORS.responseContainer) {\n const els = document.querySelectorAll(sel);\n if (els.length > 0) {\n const text = getFullText(els[els.length - 1]);\n if (text.length > 10) return text;\n }\n }\n\n // 备选:markdown 容器\n const mdEls = document.querySelectorAll('[class*=\"markdown\"], [class*=\"prose\"]');\n if (mdEls.length > 0) {\n const text = getFullText(mdEls[mdEls.length - 1]);\n if (text.length > 10) return text;\n }\n\n return '';\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 提取回复(简化版)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function extractReply(page: Page, question: string, verbose = false): Promise<string> {\n log(verbose, '提取 AI 回复...');\n\n const text = await extractLastMessage(page);\n\n if (text.length > 0) {\n const cleaned = text\n .replace(/^参考\\d+个网页\\s*/, '')\n .replace(/^深度思考已完成\\s*/, '')\n .replace(/^思考完成[::]\\s*/, '')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\n log(verbose, `提取成功: ${cleaned.length} 字符`);\n return cleaned;\n }\n\n throw new YiyanAgentError('TIMEOUT', 'Failed to extract reply');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 调试工具\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function dumpDebugInfo(page: Page): Promise<void> {\n const info = await page.evaluate(() => {\n const classFreq: Record<string, number> = {};\n document.querySelectorAll('*').forEach(el => {\n el.classList.forEach(c => {\n if (c.match(/message|chat|input|send|stop|markdown|content|assistant|user|bot|answer/i)) {\n classFreq[c] = (classFreq[c] || 0) + 1;\n }\n });\n });\n\n const inputs = Array.from(document.querySelectorAll('textarea, [contenteditable]')).map(e => ({\n tag: e.tagName,\n id: e.id || null,\n class: (e.className?.toString() || '').substring(0, 80),\n placeholder: (e as any).placeholder || null,\n editable: e.isContentEditable,\n visible: e.offsetParent !== null,\n }));\n\n return {\n url: window.location.href,\n title: document.title,\n classes: Object.entries(classFreq).sort((a, b) => b[1] - a[1]).slice(0, 40),\n inputs,\n };\n });\n\n console.log('\\n' + '═'.repeat(60));\n console.log(' DOM DEBUG INFO');\n console.log('═'.repeat(60));\n console.log('URL :', info.url);\n console.log('Title :', info.title);\n console.log('\\nInput elements:');\n info.inputs.forEach(i => console.log(' ', JSON.stringify(i)));\n console.log('\\nMatching CSS classes (by frequency):');\n info.classes.forEach(([cls, count]) => console.log(` ${String(count).padStart(3)}x .${cls}`));\n console.log('═'.repeat(60) + '\\n');\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":["DEFAULT_SESSION_DIR","fs","path","os","fs","import_path","import_os","import_fs","path","os","DEFAULT_SESSION_DIR","fs"]}
@@ -1,8 +1,32 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
1
25
  // src/postinstall.ts
2
- import { execSync } from "child_process";
3
- import path from "path";
4
- import os from "os";
5
- import fs from "fs";
26
+ var import_child_process = require("child_process");
27
+ var import_path = __toESM(require("path"));
28
+ var import_os = __toESM(require("os"));
29
+ var import_fs = __toESM(require("fs"));
6
30
  if (process.env.CI || process.env.SKIP_PLAYWRIGHT_INSTALL) {
7
31
  console.log("[yiyan-browser-agent] Skipping Playwright browser install (CI detected).");
8
32
  process.exit(0);
@@ -15,12 +39,12 @@ console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\
15
39
  console.log("");
16
40
  console.log(" \u6B63\u5728\u4E0B\u8F7D Playwright Chromium \u6D4F\u89C8\u5668...");
17
41
  console.log(" (\u53EA\u9700\u4E00\u6B21\uFF0C\u7EA6 150 MB)\n");
18
- var sessionDir = path.join(os.homedir(), ".yiyan-browser-agent", "session");
19
- fs.mkdirSync(sessionDir, { recursive: true });
42
+ var sessionDir = import_path.default.join(import_os.default.homedir(), ".yiyan-browser-agent", "session");
43
+ import_fs.default.mkdirSync(sessionDir, { recursive: true });
20
44
  console.log(` \u2713 \u914D\u7F6E\u76EE\u5F55: ${sessionDir}
21
45
  `);
22
46
  try {
23
- execSync("npx playwright install chromium", {
47
+ (0, import_child_process.execSync)("npx playwright install chromium", {
24
48
  stdio: "inherit",
25
49
  env: { ...process.env }
26
50
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["// src/postinstall.ts — Runs after `npm install yiyan-browser-agent`\n// Automatically downloads the Playwright Chromium browser.\nimport { execSync } from 'child_process';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n// Skip in CI environments\nif (process.env.CI || process.env.SKIP_PLAYWRIGHT_INSTALL) {\n console.log('[yiyan-browser-agent] Skipping Playwright browser install (CI detected).');\n process.exit(0);\n}\n\nconsole.log('');\nconsole.log('╔══════════════════════════════════════════════════╗');\nconsole.log('║ 🤖 Yiyan Browser Agent — 文心一言浏览器代理 ║');\nconsole.log('║ Setup - 正在初始化... ║');\nconsole.log('╚══════════════════════════════════════════════════╝');\nconsole.log('');\nconsole.log(' 正在下载 Playwright Chromium 浏览器...');\nconsole.log(' (只需一次,约 150 MB)\\n');\n\n// 确保配置目录存在\nconst sessionDir = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\nfs.mkdirSync(sessionDir, { recursive: true });\nconsole.log(` ✓ 配置目录: ${sessionDir}\\n`);\n\ntry {\n // 安装 Chromium\n execSync('npx playwright install chromium', {\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n console.log('');\n console.log(' ✓ 浏览器安装成功!');\n console.log('');\n console.log(' 使用方法:');\n console.log(' yiyan-browser-agent login # 首次登录');\n console.log(' yiyan-browser-agent ask \"问题\" # 提问');\n console.log('');\n console.log(' Ubuntu 用户首次使用需要先安装系统依赖:');\n console.log(' npx playwright install-deps chromium');\n console.log('');\n} catch (err) {\n console.warn('');\n console.warn(' ⚠ Chromium 自动安装失败。');\n console.warn(' 请手动运行以下命令完成安装:');\n console.warn('');\n console.warn(' npx playwright install chromium');\n console.warn(' npx playwright install-deps chromium # Ubuntu 需要');\n console.warn('');\n}"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,QAAQ;AAGf,IAAI,QAAQ,IAAI,MAAM,QAAQ,IAAI,yBAAyB;AACzD,UAAQ,IAAI,0EAA0E;AACtF,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,0TAAsD;AAClE,QAAQ,IAAI,iHAA8C;AAC1D,QAAQ,IAAI,oFAAiD;AAC7D,QAAQ,IAAI,0TAAsD;AAClE,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,sEAAmC;AAC/C,QAAQ,IAAI,mDAAqB;AAGjC,IAAM,aAAa,KAAK,KAAK,GAAG,QAAQ,GAAG,wBAAwB,SAAS;AAC5E,GAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAC5C,QAAQ,IAAI,sCAAa,UAAU;AAAA,CAAI;AAEvC,IAAI;AAEF,WAAS,mCAAmC;AAAA,IAC1C,OAAO;AAAA,IACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,EACxB,CAAC;AAED,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,2DAAc;AAC1B,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,6BAAS;AACrB,UAAQ,IAAI,uEAAmD;AAC/D,UAAQ,IAAI,mEAA+C;AAC3D,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,sGAA2B;AACvC,UAAQ,IAAI,0CAA0C;AACtD,UAAQ,IAAI,EAAE;AAChB,SAAS,KAAK;AACZ,UAAQ,KAAK,EAAE;AACf,UAAQ,KAAK,+DAAuB;AACpC,UAAQ,KAAK,mFAAkB;AAC/B,UAAQ,KAAK,EAAE;AACf,UAAQ,KAAK,qCAAqC;AAClD,UAAQ,KAAK,iEAAuD;AACpE,UAAQ,KAAK,EAAE;AACjB;","names":[]}
1
+ {"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["// src/postinstall.ts — Runs after `npm install yiyan-browser-agent`\n// Automatically downloads the Playwright Chromium browser.\nimport { execSync } from 'child_process';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\n// Skip in CI environments\nif (process.env.CI || process.env.SKIP_PLAYWRIGHT_INSTALL) {\n console.log('[yiyan-browser-agent] Skipping Playwright browser install (CI detected).');\n process.exit(0);\n}\n\nconsole.log('');\nconsole.log('╔══════════════════════════════════════════════════╗');\nconsole.log('║ 🤖 Yiyan Browser Agent — 文心一言浏览器代理 ║');\nconsole.log('║ Setup - 正在初始化... ║');\nconsole.log('╚══════════════════════════════════════════════════╝');\nconsole.log('');\nconsole.log(' 正在下载 Playwright Chromium 浏览器...');\nconsole.log(' (只需一次,约 150 MB)\\n');\n\n// 确保配置目录存在\nconst sessionDir = path.join(os.homedir(), '.yiyan-browser-agent', 'session');\nfs.mkdirSync(sessionDir, { recursive: true });\nconsole.log(` ✓ 配置目录: ${sessionDir}\\n`);\n\ntry {\n // 安装 Chromium\n execSync('npx playwright install chromium', {\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n console.log('');\n console.log(' ✓ 浏览器安装成功!');\n console.log('');\n console.log(' 使用方法:');\n console.log(' yiyan-browser-agent login # 首次登录');\n console.log(' yiyan-browser-agent ask \"问题\" # 提问');\n console.log('');\n console.log(' Ubuntu 用户首次使用需要先安装系统依赖:');\n console.log(' npx playwright install-deps chromium');\n console.log('');\n} catch (err) {\n console.warn('');\n console.warn(' ⚠ Chromium 自动安装失败。');\n console.warn(' 请手动运行以下命令完成安装:');\n console.warn('');\n console.warn(' npx playwright install chromium');\n console.warn(' npx playwright install-deps chromium # Ubuntu 需要');\n console.warn('');\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAEA,2BAAyB;AACzB,kBAAiB;AACjB,gBAAe;AACf,gBAAe;AAGf,IAAI,QAAQ,IAAI,MAAM,QAAQ,IAAI,yBAAyB;AACzD,UAAQ,IAAI,0EAA0E;AACtF,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,0TAAsD;AAClE,QAAQ,IAAI,iHAA8C;AAC1D,QAAQ,IAAI,oFAAiD;AAC7D,QAAQ,IAAI,0TAAsD;AAClE,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,sEAAmC;AAC/C,QAAQ,IAAI,mDAAqB;AAGjC,IAAM,aAAa,YAAAA,QAAK,KAAK,UAAAC,QAAG,QAAQ,GAAG,wBAAwB,SAAS;AAC5E,UAAAC,QAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAC5C,QAAQ,IAAI,sCAAa,UAAU;AAAA,CAAI;AAEvC,IAAI;AAEF,qCAAS,mCAAmC;AAAA,IAC1C,OAAO;AAAA,IACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,EACxB,CAAC;AAED,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,2DAAc;AAC1B,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,6BAAS;AACrB,UAAQ,IAAI,uEAAmD;AAC/D,UAAQ,IAAI,mEAA+C;AAC3D,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,sGAA2B;AACvC,UAAQ,IAAI,0CAA0C;AACtD,UAAQ,IAAI,EAAE;AAChB,SAAS,KAAK;AACZ,UAAQ,KAAK,EAAE;AACf,UAAQ,KAAK,+DAAuB;AACpC,UAAQ,KAAK,mFAAkB;AAC/B,UAAQ,KAAK,EAAE;AACf,UAAQ,KAAK,qCAAqC;AAClD,UAAQ,KAAK,iEAAuD;AACpE,UAAQ,KAAK,EAAE;AACjB;","names":["path","os","fs"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * yiyan-browser-agent 类型定义
3
+ */
4
+ /** 配置选项 */
5
+ interface YiyanAgentOptions {
6
+ /** 超时毫秒,默认 120000 */
7
+ timeout?: number;
8
+ /** 重试次数,默认 3 */
9
+ retryCount?: number;
10
+ /** 自定义 profile 目录 */
11
+ profileDir?: string;
12
+ /** 自定义 Chrome 可执行文件路径 */
13
+ chromePath?: string;
14
+ }
15
+ /** CLI 输出格式 */
16
+ interface CliOutput {
17
+ success: boolean;
18
+ /** 用户发送的问题 */
19
+ question: string;
20
+ /** 成功时有值 */
21
+ answer?: string;
22
+ /** 失败时有值 */
23
+ error?: string;
24
+ /** 耗时毫秒 */
25
+ duration: number;
26
+ }
27
+ /** 错误类型 */
28
+ type YiyanAgentErrorType = 'BROWSER_LAUNCH' | 'PROFILE_COPY' | 'TIMEOUT' | 'NETWORK' | 'CAPTCHA';
29
+ /** 自定义错误类 */
30
+ declare class YiyanAgentError extends Error {
31
+ type: YiyanAgentErrorType;
32
+ constructor(type: YiyanAgentErrorType, message: string);
33
+ }
34
+ /** 默认配置 */
35
+ declare const DEFAULT_OPTIONS: Required<YiyanAgentOptions>;
36
+ /** 文心一言网页 URL */
37
+ declare const YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
38
+
39
+ export { type CliOutput as C, DEFAULT_OPTIONS as D, YIYAN_CHAT_URL as Y, YiyanAgentError as a, type YiyanAgentErrorType as b, type YiyanAgentOptions as c };
package/package.json CHANGED
@@ -1,18 +1,11 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "NPM package for interacting with Yiyan (文心一言) web version via Playwright. No API key required.",
5
- "type": "module",
6
5
  "bin": {
7
6
  "yiyan-browser-agent": "./dist/cli.js"
8
7
  },
9
8
  "main": "./dist/index.js",
10
- "exports": {
11
- ".": {
12
- "import": "./dist/index.js",
13
- "types": "./dist/index.d.ts"
14
- }
15
- },
16
9
  "files": [
17
10
  "dist",
18
11
  "README.md",