yiyan-browser-agent 1.1.3 → 1.2.0

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 CHANGED
@@ -4,12 +4,13 @@ import { C as CliOutput } from './types-BhQ78DYf.js';
4
4
  declare function printHelp(): void;
5
5
  /** 解析后的 CLI 参数 */
6
6
  interface ParsedArgs {
7
- command: 'ask' | 'status' | 'reset' | 'login' | 'help' | null;
7
+ command: 'ask' | 'status' | 'reset' | 'login' | 'help' | 'config' | null;
8
8
  question?: string;
9
9
  timeout?: number;
10
10
  retry?: number;
11
11
  headful?: boolean;
12
12
  verbose?: boolean;
13
+ chromePath?: string;
13
14
  }
14
15
  /**
15
16
  * 解析 CLI 参数
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/agent.ts
4
4
  import path3 from "path";
5
- import os2 from "os";
5
+ import os3 from "os";
6
6
 
7
7
  // src/types.ts
8
8
  var YiyanAgentError = class extends Error {
@@ -23,17 +23,68 @@ var YIYAN_CHAT_URL = "https://yiyan.baidu.com/";
23
23
 
24
24
  // src/profile.ts
25
25
  import path from "path";
26
+ import os from "os";
26
27
  import fs from "fs";
27
28
  import fsp from "fs/promises";
28
- function getChromeExecutablePath(platform) {
29
+ var CONFIG_FILE_PATH = path.join(os.homedir(), ".yiyan-browser-agent", "config.json");
30
+ function readConfig() {
31
+ try {
32
+ if (fs.existsSync(CONFIG_FILE_PATH)) {
33
+ const content = fs.readFileSync(CONFIG_FILE_PATH, "utf-8");
34
+ return JSON.parse(content);
35
+ }
36
+ } catch {
37
+ }
38
+ return {};
39
+ }
40
+ function saveConfig(config) {
41
+ const configDir = path.dirname(CONFIG_FILE_PATH);
42
+ if (!fs.existsSync(configDir)) {
43
+ fs.mkdirSync(configDir, { recursive: true });
44
+ }
45
+ fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2));
46
+ }
47
+ var LINUX_CHROME_PATHS = [
48
+ "/usr/bin/google-chrome-stable",
49
+ "/usr/bin/google-chrome",
50
+ "/usr/bin/chromium-browser",
51
+ "/usr/bin/chromium",
52
+ "/snap/bin/google-chrome"
53
+ // Ubuntu snap 安装
54
+ ];
55
+ function detectLinuxChromePath() {
56
+ for (const chromePath of LINUX_CHROME_PATHS) {
57
+ if (fs.existsSync(chromePath)) {
58
+ return chromePath;
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+ function getChromeExecutablePath(platform, userPath) {
64
+ if (userPath && fs.existsSync(userPath)) {
65
+ return userPath;
66
+ }
29
67
  switch (platform) {
30
68
  case "win32":
31
69
  const programFiles = process.env.PROGRAMFILES || "C:\\Program Files";
32
- return path.join(programFiles, "Google", "Chrome", "Application", "chrome.exe");
70
+ const winPath = path.join(programFiles, "Google", "Chrome", "Application", "chrome.exe");
71
+ if (fs.existsSync(winPath)) {
72
+ return winPath;
73
+ }
74
+ const programFilesX86 = process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)";
75
+ const winPathX86 = path.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe");
76
+ if (fs.existsSync(winPathX86)) {
77
+ return winPathX86;
78
+ }
79
+ return null;
33
80
  case "darwin":
34
- return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
81
+ const macPath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
82
+ if (fs.existsSync(macPath)) {
83
+ return macPath;
84
+ }
85
+ return null;
35
86
  case "linux":
36
- return "/usr/bin/google-chrome";
87
+ return detectLinuxChromePath();
37
88
  default:
38
89
  return null;
39
90
  }
@@ -55,10 +106,10 @@ import { chromium } from "playwright-core";
55
106
  import http from "http";
56
107
  import { spawn, execSync } from "child_process";
57
108
  import path2 from "path";
58
- import os from "os";
109
+ import os2 from "os";
59
110
  import fs2 from "fs";
60
111
  var CDP_PORT = 19222;
61
- var DEBUG_DIR = path2.join(os.homedir(), ".yiyan-browser-agent", "debug");
112
+ var DEBUG_DIR = path2.join(os2.homedir(), ".yiyan-browser-agent", "debug");
62
113
  function log(verbose, msg) {
63
114
  if (verbose) {
64
115
  process.stderr.write(`[yiyan-agent] ${msg}
@@ -148,6 +199,12 @@ function waitForCDP(port, timeout = 15e3) {
148
199
  }
149
200
  async function launchBrowser(options) {
150
201
  const { chromePath, profilePath, headless, timeout = 3e4, verbose = false } = options;
202
+ if (!chromePath || !fs2.existsSync(chromePath)) {
203
+ throw new YiyanAgentError(
204
+ "BROWSER_LAUNCH",
205
+ `Chrome not found at: ${chromePath || "unknown path"}. Please install Chrome or use --chrome-path to specify a custom path.`
206
+ );
207
+ }
151
208
  try {
152
209
  log(verbose, "\u6E05\u7406\u6B8B\u7559 Chrome \u8FDB\u7A0B...");
153
210
  killProcessOnPort(CDP_PORT);
@@ -159,10 +216,18 @@ async function launchBrowser(options) {
159
216
  "--no-default-browser-check",
160
217
  "--disable-blink-features=AutomationControlled"
161
218
  ];
219
+ if (os2.platform() === "linux") {
220
+ chromeArgs.push(
221
+ "--no-sandbox",
222
+ "--disable-setuid-sandbox",
223
+ "--disable-dev-shm-usage"
224
+ );
225
+ }
162
226
  if (headless) {
163
227
  chromeArgs.push("--headless=new");
164
228
  }
165
229
  log(verbose, `\u542F\u52A8 Chrome: ${chromePath} ${headless ? "(headless)" : "(headed)"}`);
230
+ log(verbose, `Chrome \u53C2\u6570: ${chromeArgs.join(" ")}`);
166
231
  const chromeProcess = spawn(chromePath, chromeArgs, {
167
232
  detached: true,
168
233
  stdio: "ignore"
@@ -720,13 +785,14 @@ async function extractReply(page, question, verbose = false) {
720
785
 
721
786
  // src/agent.ts
722
787
  var DEFAULT_PROFILE_BASE_DIR = path3.join(
723
- os2.homedir(),
788
+ os3.homedir(),
724
789
  ".yiyan-browser-agent"
725
790
  );
726
791
  var YiyanAgent = class {
727
792
  options;
728
793
  profileDir;
729
794
  verbose;
795
+ savedChromePath;
730
796
  constructor(options) {
731
797
  this.options = {
732
798
  ...DEFAULT_OPTIONS,
@@ -734,6 +800,29 @@ var YiyanAgent = class {
734
800
  };
735
801
  this.profileDir = this.options.profileDir || DEFAULT_PROFILE_BASE_DIR;
736
802
  this.verbose = options?.verbose ?? false;
803
+ const config = readConfig();
804
+ this.savedChromePath = config.chromePath || null;
805
+ }
806
+ /**
807
+ * 保存 Chrome 路径到配置文件
808
+ */
809
+ saveChromePath(chromePath) {
810
+ saveConfig({ chromePath });
811
+ this.savedChromePath = chromePath;
812
+ }
813
+ /**
814
+ * 获取有效的 Chrome 路径
815
+ * 优先级:用户指定 > 配置文件保存 > 自动探测
816
+ */
817
+ getEffectiveChromePath(userPath) {
818
+ const platform = os3.platform();
819
+ if (userPath) {
820
+ return userPath;
821
+ }
822
+ if (this.savedChromePath) {
823
+ return this.savedChromePath;
824
+ }
825
+ return getChromeExecutablePath(platform);
737
826
  }
738
827
  /**
739
828
  * 发送问题并获取答案
@@ -762,12 +851,12 @@ var YiyanAgent = class {
762
851
  * 执行单次问答
763
852
  */
764
853
  async executeAsk(question, headful) {
765
- const platform = os2.platform();
766
- const chromePath = this.options.chromePath || getChromeExecutablePath(platform);
854
+ const platform = os3.platform();
855
+ const chromePath = this.getEffectiveChromePath(this.options.chromePath);
767
856
  if (!chromePath) {
768
857
  throw new YiyanAgentError(
769
858
  "BROWSER_LAUNCH",
770
- `Unsupported platform: ${platform}`
859
+ `Chrome not found on ${platform}. Please install Chrome or use --chrome-path to specify a custom path.`
771
860
  );
772
861
  }
773
862
  const profilePath = path3.join(this.profileDir, "chrome-profile");
@@ -804,12 +893,12 @@ var YiyanAgent = class {
804
893
  * 登录成功后,后续的 ask 调用将自动使用登录状态
805
894
  */
806
895
  async login() {
807
- const platform = os2.platform();
808
- const chromePath = this.options.chromePath || getChromeExecutablePath(platform);
896
+ const platform = os3.platform();
897
+ const chromePath = this.getEffectiveChromePath(this.options.chromePath);
809
898
  if (!chromePath) {
810
899
  throw new YiyanAgentError(
811
900
  "BROWSER_LAUNCH",
812
- `Unsupported platform: ${platform}`
901
+ `Chrome not found on ${platform}. Please install Chrome or use --chrome-path to specify a custom path.`
813
902
  );
814
903
  }
815
904
  const profilePath = path3.join(this.profileDir, "chrome-profile");
@@ -867,36 +956,49 @@ function printHelp() {
867
956
  yiyan-agent - \u6587\u5FC3\u4E00\u8A00\u6D4F\u89C8\u5668\u4EE3\u7406 CLI
868
957
 
869
958
  \u7528\u6CD5:
870
- yiyan-agent login \u9996\u6B21\u767B\u5F55\u6587\u5FC3\u4E00\u8A00\uFF08\u4F1A\u6253\u5F00\u6D4F\u89C8\u5668\u7A97\u53E3\uFF09
871
- yiyan-agent ask "\u95EE\u9898" [--timeout ms] [--retry n] [--headful] [--verbose]
872
- yiyan-agent status \u68C0\u67E5\u767B\u5F55\u72B6\u6001
873
- yiyan-agent reset \u6E05\u9664\u4FDD\u5B58\u7684 profile
959
+ yiyan-agent login [--chrome-path <path>] \u9996\u6B21\u767B\u5F55\u6587\u5FC3\u4E00\u8A00\uFF08\u4F1A\u6253\u5F00\u6D4F\u89C8\u5668\u7A97\u53E3\uFF09
960
+ yiyan-agent ask "\u95EE\u9898" [--timeout ms] [--retry n] [--headful] [--verbose] [--chrome-path <path>]
961
+ yiyan-agent status \u68C0\u67E5\u767B\u5F55\u72B6\u6001
962
+ yiyan-agent reset \u6E05\u9664\u4FDD\u5B58\u7684 profile
963
+ yiyan-agent config \u663E\u793A\u5F53\u524D\u914D\u7F6E
874
964
 
875
965
  \u547D\u4EE4:
876
966
  login \u6253\u5F00\u6D4F\u89C8\u5668\u624B\u52A8\u767B\u5F55\u6587\u5FC3\u4E00\u8A00\uFF08\u9996\u6B21\u4F7F\u7528\u5FC5\u987B\u5148\u767B\u5F55\uFF09
877
967
  ask \u53D1\u9001\u95EE\u9898\u5E76\u83B7\u53D6\u7B54\u6848\uFF08\u9ED8\u8BA4\u65E0\u5934\u6A21\u5F0F\uFF0C\u4E0D\u5F39\u7A97\uFF1B\u767B\u5F55\u540E\u76F4\u63A5\u4F7F\u7528\uFF09
878
968
  status \u68C0\u67E5\u767B\u5F55\u72B6\u6001
879
969
  reset \u6E05\u9664\u4FDD\u5B58\u7684 profile
970
+ config \u663E\u793A\u5F53\u524D\u914D\u7F6E
880
971
 
881
972
  \u9009\u9879:
882
- --timeout <ms> \u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 120000
883
- --retry <n> \u91CD\u8BD5\u6B21\u6570\uFF0C\u9ED8\u8BA4 3
884
- --headful \u4F7F\u7528\u6709\u5934\u6D4F\u89C8\u5668\uFF08\u53EF\u89C1\u7A97\u53E3\uFF0C\u7528\u4E8E\u624B\u52A8\u8FC7\u9A8C\u8BC1\u7801\uFF09
885
- --verbose \u663E\u793A\u8BE6\u7EC6\u65E5\u5FD7\uFF08\u8C03\u8BD5\u7528\uFF09
886
- --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
973
+ --timeout <ms> \u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 120000
974
+ --retry <n> \u91CD\u8BD5\u6B21\u6570\uFF0C\u9ED8\u8BA4 3
975
+ --headful \u4F7F\u7528\u6709\u5934\u6D4F\u89C8\u5668\uFF08\u53EF\u89C1\u7A97\u53E3\uFF0C\u7528\u4E8E\u624B\u52A8\u8FC7\u9A8C\u8BC1\u7801\uFF09
976
+ --verbose \u663E\u793A\u8BE6\u7EC6\u65E5\u5FD7\uFF08\u8C03\u8BD5\u7528\uFF09
977
+ --chrome-path <path> \u6307\u5B9A Chrome \u53EF\u6267\u884C\u6587\u4EF6\u8DEF\u5F84\uFF08\u4F1A\u4FDD\u5B58\u914D\u7F6E\uFF0C\u540E\u7EED\u81EA\u52A8\u4F7F\u7528\uFF09
978
+ --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
887
979
 
888
980
  \u793A\u4F8B:
889
981
  yiyan-agent login # \u9996\u6B21\u4F7F\u7528\uFF1A\u767B\u5F55\u6587\u5FC3\u4E00\u8A00
982
+ yiyan-agent login --chrome-path "/usr/bin/google-chrome-stable" # Linux \u6307\u5B9A Chrome \u8DEF\u5F84
890
983
  yiyan-agent ask "\u4EC0\u4E48\u662F TypeScript\uFF1F" # \u63D0\u95EE\uFF08\u9759\u9ED8\u6A21\u5F0F\uFF09
891
984
  yiyan-agent ask "\u89E3\u91CA Promise" --verbose # \u663E\u793A\u8BE6\u7EC6\u65E5\u5FD7
892
985
  yiyan-agent ask "30+30=" --headful # \u6709\u5934\u6A21\u5F0F\uFF08\u53EF\u624B\u52A8\u8FC7\u9A8C\u8BC1\u7801\uFF09
893
986
  yiyan-agent status
894
987
  yiyan-agent reset
988
+ yiyan-agent config # \u663E\u793A\u4FDD\u5B58\u7684 Chrome \u8DEF\u5F84\u7B49\u914D\u7F6E
895
989
 
896
990
  \u6D41\u7A0B:
897
991
  1. \u5148\u8FD0\u884C yiyan-agent login \u767B\u5F55\uFF08\u53EA\u9700\u4E00\u6B21\uFF0C\u767B\u5F55\u72B6\u6001\u4F1A\u4FDD\u5B58\uFF09
898
992
  2. \u4E4B\u540E\u76F4\u63A5 yiyan-agent ask "\u95EE\u9898" \u5373\u53EF\uFF0C\u65E0\u9700\u518D\u767B\u5F55
899
993
  3. \u5982\u679C\u9047\u5230\u9A8C\u8BC1\u7801\uFF0C\u52A0 --headful \u5207\u6362\u6709\u5934\u6A21\u5F0F\u624B\u52A8\u5904\u7406
994
+
995
+ Linux \u63D0\u793A:
996
+ \u5982\u679C login \u6CA1\u6709\u53CD\u5E94\uFF0C\u8BF7\u5C1D\u8BD5\u6307\u5B9A Chrome \u8DEF\u5F84\uFF1A
997
+ yiyan-agent login --chrome-path "/usr/bin/google-chrome-stable"
998
+ \u5E38\u89C1\u8DEF\u5F84\uFF1A
999
+ /usr/bin/google-chrome-stable (Debian/Ubuntu apt \u5B89\u88C5)
1000
+ /usr/bin/chromium-browser (\u67D0\u4E9B Ubuntu \u7248\u672C)
1001
+ /snap/bin/google-chrome (Ubuntu snap \u5B89\u88C5)
900
1002
  `);
901
1003
  }
902
1004
  function parseCliArgs(args) {
@@ -925,6 +1027,9 @@ function parseCliArgs(args) {
925
1027
  if (arg === "login") {
926
1028
  result.command = "login";
927
1029
  }
1030
+ if (arg === "config") {
1031
+ result.command = "config";
1032
+ }
928
1033
  if (arg === "--timeout") {
929
1034
  if (i + 1 < args.length) {
930
1035
  result.timeout = parseInt(args[i + 1], 10);
@@ -943,6 +1048,12 @@ function parseCliArgs(args) {
943
1048
  if (arg === "--verbose") {
944
1049
  result.verbose = true;
945
1050
  }
1051
+ if (arg === "--chrome-path") {
1052
+ if (i + 1 < args.length) {
1053
+ result.chromePath = args[i + 1];
1054
+ i++;
1055
+ }
1056
+ }
946
1057
  }
947
1058
  return result;
948
1059
  }
@@ -965,11 +1076,33 @@ async function runCli(args) {
965
1076
  if (parsed.verbose) {
966
1077
  options.verbose = true;
967
1078
  }
1079
+ if (parsed.chromePath) {
1080
+ options.chromePath = parsed.chromePath;
1081
+ }
968
1082
  const agent = new YiyanAgent(options);
1083
+ if (parsed.command === "config") {
1084
+ const status = agent.status();
1085
+ const configInfo = {
1086
+ ...status,
1087
+ savedChromePath: parsed.chromePath || void 0
1088
+ };
1089
+ console.log(formatCliOutput({
1090
+ success: true,
1091
+ question: "config",
1092
+ answer: JSON.stringify(configInfo, null, 2),
1093
+ duration: 0
1094
+ }));
1095
+ return;
1096
+ }
969
1097
  if (parsed.command === "login") {
970
- console.log("Opening browser for login... Please login to Yiyan (\u6587\u5FC3\u4E00\u8A00) in the browser window.");
1098
+ if (parsed.verbose) {
1099
+ console.log("Opening browser for login... Please login to Yiyan (\u6587\u5FC3\u4E00\u8A00) in the browser window.");
1100
+ }
971
1101
  try {
972
1102
  await agent.login();
1103
+ if (parsed.chromePath) {
1104
+ agent.saveChromePath(parsed.chromePath);
1105
+ }
973
1106
  console.log(formatCliOutput({
974
1107
  success: true,
975
1108
  question: "login",