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 +2 -1
- package/dist/cli.js +157 -24
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +108 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
109
|
+
import os2 from "os";
|
|
59
110
|
import fs2 from "fs";
|
|
60
111
|
var CDP_PORT = 19222;
|
|
61
|
-
var DEBUG_DIR = path2.join(
|
|
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
|
-
|
|
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 =
|
|
766
|
-
const chromePath = this.options.chromePath
|
|
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
|
-
`
|
|
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 =
|
|
808
|
-
const chromePath = this.options.chromePath
|
|
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
|
-
`
|
|
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
|
|
871
|
-
yiyan-agent ask "\u95EE\u9898" [--timeout ms] [--retry n] [--headful] [--verbose]
|
|
872
|
-
yiyan-agent status
|
|
873
|
-
yiyan-agent reset
|
|
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>
|
|
883
|
-
--retry <n>
|
|
884
|
-
--headful
|
|
885
|
-
--verbose
|
|
886
|
-
--
|
|
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
|
-
|
|
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",
|