dsh-web-search-pro 0.1.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/LICENSE +21 -0
- package/LOGIN.md +67 -0
- package/README.md +123 -0
- package/cordis.patch.yml +21 -0
- package/lib/browser-service.d.ts +68 -0
- package/lib/browser-service.js +8 -0
- package/lib/browser-service.js.map +1 -0
- package/lib/config.d.ts +91 -0
- package/lib/config.js +72 -0
- package/lib/config.js.map +1 -0
- package/lib/deps.d.ts +34 -0
- package/lib/deps.js +90 -0
- package/lib/deps.js.map +1 -0
- package/lib/engines.d.ts +71 -0
- package/lib/engines.js +562 -0
- package/lib/engines.js.map +1 -0
- package/lib/extract.d.ts +40 -0
- package/lib/extract.js +243 -0
- package/lib/extract.js.map +1 -0
- package/lib/fetch.d.ts +42 -0
- package/lib/fetch.js +175 -0
- package/lib/fetch.js.map +1 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +117 -0
- package/lib/index.js.map +1 -0
- package/lib/memory-cache.d.ts +18 -0
- package/lib/memory-cache.js +42 -0
- package/lib/memory-cache.js.map +1 -0
- package/lib/platform-search.d.ts +34 -0
- package/lib/platform-search.js +61 -0
- package/lib/platform-search.js.map +1 -0
- package/lib/playwright.d.ts +71 -0
- package/lib/playwright.js +165 -0
- package/lib/playwright.js.map +1 -0
- package/lib/router.d.ts +66 -0
- package/lib/router.js +332 -0
- package/lib/router.js.map +1 -0
- package/lib/store.d.ts +117 -0
- package/lib/store.js +223 -0
- package/lib/store.js.map +1 -0
- package/lib/tools.d.ts +28 -0
- package/lib/tools.js +542 -0
- package/lib/tools.js.map +1 -0
- package/lib/util.d.ts +73 -0
- package/lib/util.js +220 -0
- package/lib/util.js.map +1 -0
- package/package.json +59 -0
- package/scripts/save-login.mjs +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-web-search-pro contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/LOGIN.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# 中文社区平台登录态(复用你已登录的浏览器)
|
|
2
|
+
|
|
3
|
+
知乎 / 微博 / 豆瓣 / 贴吧 / 抖音 / 快手 / 小红书的搜索页都有反爬与登录墙,
|
|
4
|
+
免登录的公开接口基本都被风控。所以这些平台走 **Playwright 驱动登录态浏览器** 的路径:
|
|
5
|
+
在你已登录的浏览器里打开搜索页、读渲染结果——不需要逆向任何签名。
|
|
6
|
+
|
|
7
|
+
## 方式一:登录一次保存登录态(推荐)
|
|
8
|
+
|
|
9
|
+
运行插件包里的脚本,按提示逐个平台登录一次(扫码/账号密码),
|
|
10
|
+
脚本会把所有 cookies 合并保存成一个 storageState JSON:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cd dsh-web-search-pro
|
|
14
|
+
node scripts/save-login.mjs all login-state.json
|
|
15
|
+
# 或只登录一个平台:
|
|
16
|
+
node scripts/save-login.mjs zhihu login-state.json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
然后把文件路径填到 `$DSH_HOME/settings.yaml`:
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
web-search-pro:
|
|
23
|
+
playwright:
|
|
24
|
+
storageStatePath: 'login-state.json' # 绝对路径更稳
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> storageState 是 Playwright 的标准登录态文件(cookies + origins),
|
|
28
|
+
> 同一份文件可同时含多个站点的登录态(脚本会依次登录并合并)。
|
|
29
|
+
|
|
30
|
+
## 方式二:用 Cookie 插件导出
|
|
31
|
+
|
|
32
|
+
如果你更习惯手动导出:
|
|
33
|
+
|
|
34
|
+
1. 在浏览器装 Cookie-Editor(或 EditThisCookie)。
|
|
35
|
+
2. 在目标站点导出 cookies(JSON)。
|
|
36
|
+
3. 组装成 storageState 格式:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{ "cookies": [ ...导出的 cookies... ], "origins": [] }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
每个 cookie 至少需要 `name` `value` `domain` `path`(可补 `expires` `httpOnly` `secure`)。
|
|
43
|
+
|
|
44
|
+
## 结果选择器可配置
|
|
45
|
+
|
|
46
|
+
站点改版后如果提取不到结果,不用改代码——在 `settings.yaml` 按平台覆盖选择器:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
web-search-pro:
|
|
50
|
+
platformRules:
|
|
51
|
+
zhihu:
|
|
52
|
+
item: '.SearchResult-Card'
|
|
53
|
+
title: '.ContentItem-title'
|
|
54
|
+
link: '.ContentItem-title a'
|
|
55
|
+
text: '.Highlight'
|
|
56
|
+
weibo:
|
|
57
|
+
item: '.card-wrap'
|
|
58
|
+
title: '.txt'
|
|
59
|
+
link: '.from a'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 安全与合规提醒
|
|
63
|
+
|
|
64
|
+
- 仅做**单次、低频**的搜索调用,不要批量爬取;遵守目标平台的服务条款与 robots.txt。
|
|
65
|
+
- 登录态文件包含你的登录凭据,请勿提交到公开仓库或分享给他人。
|
|
66
|
+
- 本能力借鉴 MediaCrawler 的思路(登录态浏览器驱动搜索页),
|
|
67
|
+
但为 MIT 许可的独立实现,未使用其 NON-COMMERCIAL 许可下的签名算法代码。
|
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# dsh-web-search-pro
|
|
2
|
+
|
|
3
|
+
增强型、可持久化的扩展网页搜索插件 for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)。
|
|
4
|
+
|
|
5
|
+
一个 DSH **bundle 插件**,把多引擎网页搜索、平台搜索、持久化缓存、脚本猫式按站提取、Playwright 渲染打包成模型可直接调用的 9 个工具。灵感来自 [MediaCrawler](https://github.com/NanmiCoder/MediaCrawler)、[Agent-Reach](https://github.com/Panniantong/Agent-Reach)、脚本猫/油猴 userscript、opencli 与 playwright。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
dsh plugin --profile web add dsh-web-search-pro # 自动装 dsh-browser(dependency)+ 自动挂载 browser 行(本 patch)
|
|
11
|
+
# 或本地目录 / tarball:
|
|
12
|
+
dsh plugin --profile web add ./dsh-web-search-pro
|
|
13
|
+
# 重启(web profile 关闭了 HMR):
|
|
14
|
+
dsh --profile web
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
> dsh-browser 需先发布到 npm(本地测试可用 `dsh plugin --profile web add ../dsh-browser ../dsh-web-search-pro` 一条命令显式列两个)。
|
|
18
|
+
> 依赖 `@deepseek-ai/*` 已发布到 npm(`^0.1.0-rc.6`,与社区 dsh-cc-tui 一致)。
|
|
19
|
+
> 若你的 harness 是本地源码 checkout(如 `0.1.0-rc.5`),版本号可能有出入——用
|
|
20
|
+
> `dsh plugin --profile web add ./<path>` 并在 profile 的 `pnpm-workspace.yaml`
|
|
21
|
+
> 里对齐版本后重装即可。
|
|
22
|
+
|
|
23
|
+
## 工具(9 个)
|
|
24
|
+
|
|
25
|
+
| 工具 | 作用 |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `web_search_pro` | 多引擎搜索 + RRF 融合 + 内存/SQLite 双层缓存 + 历史 |
|
|
28
|
+
| `web_fetch_pro` | 可读化抓取(Jina → HTTP+规则抽取 → Playwright 兜底)+ 快照缓存 |
|
|
29
|
+
| `web_platform_search` | 20 平台:GitHub/B站/YouTube/V2EX/小红书/Twitter/Reddit/IG/FB/RSS + 知乎/微博/豆瓣/贴吧/抖音/快手(Playwright 登录态) |
|
|
30
|
+
| `web_snapshot` | Playwright 全页截图 + HTML + 文本落盘 |
|
|
31
|
+
| `web_history` / `web_cache_clear` / `web_search_stats` | 持久历史 / 清缓存 / 存储统计 |
|
|
32
|
+
| `web_rule` | 持久化按站提取规则(脚本猫式,list/upsert/remove) |
|
|
33
|
+
| `web_deps` | 检测/安装外部依赖(gh/bili/yt-dlp/opencli/agent-reach/mcporter/playwright) |
|
|
34
|
+
|
|
35
|
+
## 配置
|
|
36
|
+
|
|
37
|
+
三层,越靠前越日常:
|
|
38
|
+
|
|
39
|
+
1. **`$DSH_HOME/settings.yaml` → `web-search-pro:` 段**(热重载,改完即生效):
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
web-search-pro:
|
|
43
|
+
exaApiKey: 'sk-...' # 或环境变量 EXA_API_KEY / .credentials.yaml
|
|
44
|
+
jinaApiKey: 'jina_...' # 或环境变量 JINA_API_KEY
|
|
45
|
+
engines: [ddg, bing, exa, seam, jina]
|
|
46
|
+
parallelEngines: false
|
|
47
|
+
ttlSeconds: 3600
|
|
48
|
+
searchMaxResults: 8
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
2. **cordis.yml `config:`**(部署级默认值,见 `cordis.patch.yml`)。
|
|
52
|
+
3. **环境变量 / 凭据**:`$EXA_API_KEY`、`$JINA_API_KEY`(`exaApiKeyEnv`/`jinaApiKeyEnv` 引用)。
|
|
53
|
+
|
|
54
|
+
## 外部依赖(按需)
|
|
55
|
+
|
|
56
|
+
多数后端需要系统额外安装的工具;插件提供 `web_deps` 工具检测与安装:
|
|
57
|
+
|
|
58
|
+
| 依赖 | 用途 | 安装 |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| gh | GitHub 后端 | `winget install GitHub.cli` / `choco install gh` |
|
|
61
|
+
| bili-cli | B站后端 | `uv tool install bili-cli` / `pipx install bili-cli` |
|
|
62
|
+
| yt-dlp | YouTube 后端 | `uv tool install yt-dlp` / `pip install yt-dlp` |
|
|
63
|
+
| opencli | 小红书/Twitter/Reddit/IG/FB | `npm i -g opencli` |
|
|
64
|
+
| agent-reach | agent-reach 后端 | `uv tool install agent-reach` / `pip install agent-reach` |
|
|
65
|
+
| playwright | 渲染/截图后端 | `npm i -g playwright && playwright install chromium` |
|
|
66
|
+
|
|
67
|
+
## 平台与引擎
|
|
68
|
+
|
|
69
|
+
`seam`(ctx.web/DeepSeek 原生)· `exa` · `ddg` · `bing` · `jina` · `github` · `bilibili` · `v2ex` · `youtube`。默认顺序 `ddg, bing, exa, seam, jina`(免费优先),失败自动回退;`multi` 并行融合。
|
|
70
|
+
|
|
71
|
+
## 开发
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm install
|
|
75
|
+
pnpm build # tsc src → lib
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
源码在 `src/`;`lib/` 为发布产物(已提交)。
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## 中文社区平台登录态
|
|
86
|
+
|
|
87
|
+
zhihu / weibo / douban / tieba / douyin / kuaishou 的免登录公开接口都被风控,
|
|
88
|
+
所以走 **Playwright 驱动登录态浏览器**(借鉴 MediaCrawler 思路、MIT 独立实现,未用其签名算法):
|
|
89
|
+
|
|
90
|
+
1. 登录一次保存登录态:`node scripts/save-login.mjs all login-state.json`
|
|
91
|
+
2. 在 `$DSH_HOME/settings.yaml` 里设 `playwright.storageStatePath`
|
|
92
|
+
3. 站点改版时无需改代码,用 `platformRules` 按平台覆盖结果选择器
|
|
93
|
+
|
|
94
|
+
详见 [LOGIN.md](./LOGIN.md)。
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## 历史管理
|
|
98
|
+
|
|
99
|
+
web_history 支持:kind/query/engine/platform 过滤、replay(用 queryId 回放已存结果)、
|
|
100
|
+
export(把过滤后的历史+结果写成 JSON 文件)。
|
|
101
|
+
|
|
102
|
+
## 自定义平台(解析 cookie 去搜索)
|
|
103
|
+
|
|
104
|
+
在 settings.yaml 里定义任意站点(URL 模板 + 结果选择器 + 可选 Cookie),
|
|
105
|
+
web_platform_search 就能直接搜它——不需要改代码:
|
|
106
|
+
|
|
107
|
+
web-search-pro:
|
|
108
|
+
customPlatforms:
|
|
109
|
+
mybili:
|
|
110
|
+
name: '我的B站'
|
|
111
|
+
url: 'https://search.bilibili.com/all?keyword={query}'
|
|
112
|
+
item: '.bili-video-card'
|
|
113
|
+
title: '.bili-video-card__info--tit'
|
|
114
|
+
link: 'a'
|
|
115
|
+
# 需要登录的站点补 cookie(a=b; c=d,自动应用到 url 域名)
|
|
116
|
+
myforum:
|
|
117
|
+
name: '某论坛'
|
|
118
|
+
url: 'https://forum.example.com/search?q={query}'
|
|
119
|
+
item: '.thread'
|
|
120
|
+
title: '.thread-title a'
|
|
121
|
+
link: '.thread-title a'
|
|
122
|
+
cookie: 'sessionid=abc123; csrftoken=xyz'
|
|
123
|
+
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# dsh-web-search-pro bundle patch.
|
|
2
|
+
#
|
|
3
|
+
# Install (self-contained — also pulls in dsh-browser as a dependency):
|
|
4
|
+
# dsh plugin --profile <name> add dsh-web-search-pro
|
|
5
|
+
#
|
|
6
|
+
# The patch inserts BOTH rows: browser (the dsh-browser runtime this plugin
|
|
7
|
+
# injects) and web-search-pro. dsh-browser is declared as a regular
|
|
8
|
+
# dependency in package.json, so pnpm installs it; because dsh plugin
|
|
9
|
+
# reconcile only auto-mounts DIRECT dependencies' patches, the parent plugin
|
|
10
|
+
# inserts the child's row here so one command activates both.
|
|
11
|
+
- insert:
|
|
12
|
+
- id: browser
|
|
13
|
+
name: dsh-browser
|
|
14
|
+
config:
|
|
15
|
+
channel: chromium
|
|
16
|
+
headless: true
|
|
17
|
+
opencliEnabled: true
|
|
18
|
+
- id: web-search-pro
|
|
19
|
+
name: dsh-web-search-pro
|
|
20
|
+
config:
|
|
21
|
+
verbose: false
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer-side contract for the `browser` service provided by the dsh-browser
|
|
3
|
+
* plugin. web-search-pro injects it (inject: ['browser']) and calls these
|
|
4
|
+
* methods instead of its former local PlaywrightManager / global opencli.
|
|
5
|
+
* @module web-search-pro/browser-service
|
|
6
|
+
*/
|
|
7
|
+
export interface RenderRule {
|
|
8
|
+
hostname: string;
|
|
9
|
+
contentSelectors: string[];
|
|
10
|
+
removeSelectors?: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface BrowserRenderResult {
|
|
13
|
+
title: string;
|
|
14
|
+
text: string;
|
|
15
|
+
html: string;
|
|
16
|
+
usedRule?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BrowserSnapshotResult {
|
|
19
|
+
title: string;
|
|
20
|
+
text: string;
|
|
21
|
+
screenshotPath: string;
|
|
22
|
+
htmlPath: string;
|
|
23
|
+
usedRule?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface BrowserSearchItem {
|
|
26
|
+
url: string;
|
|
27
|
+
title: string;
|
|
28
|
+
snippet?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface BrowserCliResult {
|
|
31
|
+
code: number;
|
|
32
|
+
stdout: string;
|
|
33
|
+
stderr: string;
|
|
34
|
+
timedOut: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface BrowserService {
|
|
37
|
+
render(url: string, rules: readonly RenderRule[], opts?: {
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
maxChars?: number;
|
|
40
|
+
waitMs?: number;
|
|
41
|
+
}): Promise<BrowserRenderResult>;
|
|
42
|
+
snapshot(url: string, rules: readonly RenderRule[], opts: {
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
outDir: string;
|
|
45
|
+
maxChars?: number;
|
|
46
|
+
}): Promise<BrowserSnapshotResult>;
|
|
47
|
+
searchResults(url: string, spec: {
|
|
48
|
+
item: string;
|
|
49
|
+
title: string;
|
|
50
|
+
link: string;
|
|
51
|
+
text?: string;
|
|
52
|
+
}, opts?: {
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
count?: number;
|
|
55
|
+
waitMs?: number;
|
|
56
|
+
cookies?: {
|
|
57
|
+
name: string;
|
|
58
|
+
value: string;
|
|
59
|
+
domain: string;
|
|
60
|
+
path: string;
|
|
61
|
+
}[];
|
|
62
|
+
}): Promise<BrowserSearchItem[]>;
|
|
63
|
+
opencli(args: string[], opts?: {
|
|
64
|
+
timeoutMs?: number;
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
}): Promise<BrowserCliResult>;
|
|
67
|
+
close(): Promise<void>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer-side contract for the `browser` service provided by the dsh-browser
|
|
3
|
+
* plugin. web-search-pro injects it (inject: ['browser']) and calls these
|
|
4
|
+
* methods instead of its former local PlaywrightManager / global opencli.
|
|
5
|
+
* @module web-search-pro/browser-service
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=browser-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-service.js","sourceRoot":"","sources":["../src/browser-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin configuration (schemastery) and the resolved runtime shape.
|
|
3
|
+
* @module web-search-pro/config
|
|
4
|
+
*/
|
|
5
|
+
import z from '@deepseek-ai/schemastery';
|
|
6
|
+
/** A user-defined custom platform: search URL template + result selectors + optional login cookie. */
|
|
7
|
+
export interface CustomPlatformSpec {
|
|
8
|
+
name: string;
|
|
9
|
+
/** Search-page URL template; `{query}` is replaced with the URL-encoded query. */
|
|
10
|
+
url: string;
|
|
11
|
+
item: string;
|
|
12
|
+
title: string;
|
|
13
|
+
link: string;
|
|
14
|
+
text?: string;
|
|
15
|
+
/** Optional raw Cookie header (`a=b; c=d`); cookies are applied to the URL's domain. */
|
|
16
|
+
cookie?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Config {
|
|
19
|
+
/** SQLite database path; defaults to $DSH_HOME/data/web-search-pro/store.db */
|
|
20
|
+
dbPath?: string;
|
|
21
|
+
/** Cache freshness window in seconds. */
|
|
22
|
+
ttlSeconds: number;
|
|
23
|
+
/** In-process LRU entry cap (hot queries resolve without touching SQLite). */
|
|
24
|
+
memoryCacheEntries: number;
|
|
25
|
+
/** Reciprocal Rank Fusion constant for multi-engine merging. */
|
|
26
|
+
rrfConstant: number;
|
|
27
|
+
/** Max recency bonus added to a source's fusion score (0..1). */
|
|
28
|
+
freshnessBoost: number;
|
|
29
|
+
/** Days over which the recency bonus decays to zero. */
|
|
30
|
+
freshnessDays: number;
|
|
31
|
+
/** Max authority-domain bonus added to a source's fusion score (0..1). */
|
|
32
|
+
authorityBoost: number;
|
|
33
|
+
/** Extra authority domains (beyond the built-in .edu/.gov/.org and the curated list). */
|
|
34
|
+
authorityDomains: string[];
|
|
35
|
+
/** Default cap on returned sources per search. */
|
|
36
|
+
searchMaxResults: number;
|
|
37
|
+
/** Cooperative per-call timeout budget in ms. */
|
|
38
|
+
timeoutMs: number;
|
|
39
|
+
/** Ordered engine list for web_search_pro. */
|
|
40
|
+
engines: string[];
|
|
41
|
+
/** Query all requested engines in parallel and merge. */
|
|
42
|
+
parallelEngines: boolean;
|
|
43
|
+
/** Exa API key (falls back to $EXA_API_KEY / credentials ref). */
|
|
44
|
+
exaApiKey?: string;
|
|
45
|
+
/** Credential/env reference for the Exa key; defaults to EXA_API_KEY. */
|
|
46
|
+
exaApiKeyEnv?: string;
|
|
47
|
+
/** Jina AI API key (falls back to $JINA_API_KEY / credentials ref). */
|
|
48
|
+
jinaApiKey?: string;
|
|
49
|
+
/** Credential/env reference for the Jina key; defaults to JINA_API_KEY. */
|
|
50
|
+
jinaApiKeyEnv?: string;
|
|
51
|
+
/** Allow CLI backends (gh / bili / yt-dlp / opencli / agent-reach). */
|
|
52
|
+
enableCliBackends: boolean;
|
|
53
|
+
/** Allow opencli browser-session backends. */
|
|
54
|
+
opencliEnabled: boolean;
|
|
55
|
+
/** Allow agent-reach backends. */
|
|
56
|
+
agentReachEnabled: boolean;
|
|
57
|
+
/** Provider id registered into ctx.web for the built-in web_search tool. */
|
|
58
|
+
providerId: string;
|
|
59
|
+
/** Register the ctx.web provider (set DSH_WEB_SEARCH_PROVIDER to use it). */
|
|
60
|
+
registerProvider: boolean;
|
|
61
|
+
/** Per-platform search-page selector overrides (item/title/link/text). Overrides built-in specs. */
|
|
62
|
+
platformRules?: Record<string, {
|
|
63
|
+
item: string;
|
|
64
|
+
title: string;
|
|
65
|
+
link: string;
|
|
66
|
+
text?: string;
|
|
67
|
+
}>;
|
|
68
|
+
/** User-defined custom platform search: url template + selectors + optional cookie. */
|
|
69
|
+
customPlatforms?: Record<string, CustomPlatformSpec>;
|
|
70
|
+
/** Snapshot options. The browser runtime itself (channel/headless/storageStatePath) is provided by the dsh-browser plugin via the `browser` service. */
|
|
71
|
+
playwright: {
|
|
72
|
+
/** Gate the playwright fallback backend in web_fetch_pro. */
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
/** Directory for web_snapshot artifacts; defaults to <dbDir>/snapshots. */
|
|
75
|
+
snapshotDir?: string;
|
|
76
|
+
};
|
|
77
|
+
verbose: boolean;
|
|
78
|
+
}
|
|
79
|
+
export declare const Config: z<Config>;
|
|
80
|
+
export interface ResolvedConfig extends Config {
|
|
81
|
+
dbPath: string;
|
|
82
|
+
exaApiKey?: string;
|
|
83
|
+
exaApiKeyEnv: string;
|
|
84
|
+
jinaApiKey?: string;
|
|
85
|
+
jinaApiKeyEnv: string;
|
|
86
|
+
playwright: Required<Pick<Config['playwright'], 'enabled' | 'snapshotDir'>>;
|
|
87
|
+
}
|
|
88
|
+
/** Default database path under the harness home. */
|
|
89
|
+
export declare function defaultDbPath(): string;
|
|
90
|
+
/** Resolve a fully-defaulted config from user input. */
|
|
91
|
+
export declare function resolveConfig(config: Config): ResolvedConfig;
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin configuration (schemastery) and the resolved runtime shape.
|
|
3
|
+
* @module web-search-pro/config
|
|
4
|
+
*/
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import z from '@deepseek-ai/schemastery';
|
|
8
|
+
export const Config = z.object({
|
|
9
|
+
dbPath: z.string(),
|
|
10
|
+
ttlSeconds: z.number().default(3600),
|
|
11
|
+
memoryCacheEntries: z.number().default(128),
|
|
12
|
+
rrfConstant: z.number().default(60),
|
|
13
|
+
freshnessBoost: z.number().default(0.2),
|
|
14
|
+
freshnessDays: z.number().default(30),
|
|
15
|
+
authorityBoost: z.number().default(0.25),
|
|
16
|
+
authorityDomains: z.array(z.string()).default([]),
|
|
17
|
+
searchMaxResults: z.number().default(8),
|
|
18
|
+
timeoutMs: z.number().default(30_000),
|
|
19
|
+
engines: z.array(z.string()).default(['ddg', 'bing', 'exa', 'seam', 'jina']),
|
|
20
|
+
parallelEngines: z.boolean().default(false),
|
|
21
|
+
exaApiKey: z.string().role('secret'),
|
|
22
|
+
exaApiKeyEnv: z.string().default('EXA_API_KEY'),
|
|
23
|
+
jinaApiKey: z.string().role('secret'),
|
|
24
|
+
jinaApiKeyEnv: z.string().default('JINA_API_KEY'),
|
|
25
|
+
enableCliBackends: z.boolean().default(true),
|
|
26
|
+
opencliEnabled: z.boolean().default(true),
|
|
27
|
+
agentReachEnabled: z.boolean().default(true),
|
|
28
|
+
providerId: z.string().default('web-search-pro'),
|
|
29
|
+
registerProvider: z.boolean().default(false),
|
|
30
|
+
platformRules: z.dict(z.object({
|
|
31
|
+
item: z.string(),
|
|
32
|
+
title: z.string(),
|
|
33
|
+
link: z.string(),
|
|
34
|
+
text: z.string(),
|
|
35
|
+
})),
|
|
36
|
+
customPlatforms: z.dict(z.object({
|
|
37
|
+
name: z.string(),
|
|
38
|
+
url: z.string(),
|
|
39
|
+
item: z.string(),
|
|
40
|
+
title: z.string(),
|
|
41
|
+
link: z.string(),
|
|
42
|
+
text: z.string(),
|
|
43
|
+
cookie: z.string(),
|
|
44
|
+
})),
|
|
45
|
+
playwright: z.object({
|
|
46
|
+
enabled: z.boolean().default(true),
|
|
47
|
+
snapshotDir: z.string(),
|
|
48
|
+
}),
|
|
49
|
+
verbose: z.boolean().default(false),
|
|
50
|
+
});
|
|
51
|
+
/** Default database path under the harness home. */
|
|
52
|
+
export function defaultDbPath() {
|
|
53
|
+
const home = process.env.DSH_HOME ?? path.join(os.homedir(), '.dsh');
|
|
54
|
+
return path.join(home, 'data', 'web-search-pro', 'store.db');
|
|
55
|
+
}
|
|
56
|
+
/** Resolve a fully-defaulted config from user input. */
|
|
57
|
+
export function resolveConfig(config) {
|
|
58
|
+
const dbPath = config.dbPath ?? defaultDbPath();
|
|
59
|
+
const pw = config.playwright ?? {};
|
|
60
|
+
const snapshotDir = pw.snapshotDir ?? path.join(path.dirname(dbPath), 'snapshots');
|
|
61
|
+
return {
|
|
62
|
+
...config,
|
|
63
|
+
dbPath,
|
|
64
|
+
exaApiKeyEnv: config.exaApiKeyEnv ?? 'EXA_API_KEY',
|
|
65
|
+
jinaApiKeyEnv: config.jinaApiKeyEnv ?? 'JINA_API_KEY',
|
|
66
|
+
playwright: {
|
|
67
|
+
enabled: pw.enabled ?? true,
|
|
68
|
+
snapshotDir,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/lib/deps.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependency detection and install for the CLI/platform backends.
|
|
3
|
+
* Most backends shell out to tools installed outside DSH (gh, bili, yt-dlp,
|
|
4
|
+
* opencli, agent-reach, playwright, mcporter). This module reports which are
|
|
5
|
+
* present and how to install them; the web_deps tool exposes it to the model.
|
|
6
|
+
*
|
|
7
|
+
* Install is intentionally a MODEL-FACING TOOL, not a browser settings button:
|
|
8
|
+
* a browser button running winget/pip/npm would be arbitrary command execution
|
|
9
|
+
* without a permission gate, whereas a tool flows through DSH's existing
|
|
10
|
+
* tool-permission/approval pipeline. The card points at this tool instead.
|
|
11
|
+
* @module web-search-pro/deps
|
|
12
|
+
*/
|
|
13
|
+
export interface DepInfo {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
/** Backend that needs it. */
|
|
17
|
+
usedBy: string;
|
|
18
|
+
available: boolean;
|
|
19
|
+
path?: string;
|
|
20
|
+
installs: {
|
|
21
|
+
installer: string;
|
|
22
|
+
command: string;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
/** Detect all backends. */
|
|
26
|
+
export declare function detectDeps(): Promise<DepInfo[]>;
|
|
27
|
+
/** Run the install command for one backend + installer. */
|
|
28
|
+
export declare function installDep(id: string, installer: string): Promise<{
|
|
29
|
+
code: number;
|
|
30
|
+
stdout: string;
|
|
31
|
+
stderr: string;
|
|
32
|
+
timedOut: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const DEP_IDS: string[];
|
package/lib/deps.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependency detection and install for the CLI/platform backends.
|
|
3
|
+
* Most backends shell out to tools installed outside DSH (gh, bili, yt-dlp,
|
|
4
|
+
* opencli, agent-reach, playwright, mcporter). This module reports which are
|
|
5
|
+
* present and how to install them; the web_deps tool exposes it to the model.
|
|
6
|
+
*
|
|
7
|
+
* Install is intentionally a MODEL-FACING TOOL, not a browser settings button:
|
|
8
|
+
* a browser button running winget/pip/npm would be arbitrary command execution
|
|
9
|
+
* without a permission gate, whereas a tool flows through DSH's existing
|
|
10
|
+
* tool-permission/approval pipeline. The card points at this tool instead.
|
|
11
|
+
* @module web-search-pro/deps
|
|
12
|
+
*/
|
|
13
|
+
import { runCli } from "./util.js";
|
|
14
|
+
const IS_WIN = process.platform === 'win32';
|
|
15
|
+
/** One external tool the plugin may shell out to. */
|
|
16
|
+
const DEPS = [
|
|
17
|
+
{
|
|
18
|
+
id: 'gh', label: 'GitHub CLI', usedBy: 'github 后端',
|
|
19
|
+
installs: [
|
|
20
|
+
{ installer: 'winget', command: 'winget install GitHub.cli' },
|
|
21
|
+
{ installer: 'choco', command: 'choco install gh' },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'bili', label: 'bili-cli', usedBy: 'bilibili 后端',
|
|
26
|
+
installs: [
|
|
27
|
+
{ installer: 'uv', command: 'uv tool install bili-cli' },
|
|
28
|
+
{ installer: 'pipx', command: 'pipx install bili-cli' },
|
|
29
|
+
{ installer: 'pip', command: 'pip install bili-cli' },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'yt-dlp', label: 'yt-dlp', usedBy: 'youtube 后端',
|
|
34
|
+
installs: [
|
|
35
|
+
{ installer: 'uv', command: 'uv tool install yt-dlp' },
|
|
36
|
+
{ installer: 'pip', command: 'pip install yt-dlp' },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'agent-reach', label: 'Agent-Reach', usedBy: 'agent-reach 后端',
|
|
41
|
+
installs: [
|
|
42
|
+
{ installer: 'uv', command: 'uv tool install agent-reach' },
|
|
43
|
+
{ installer: 'pip', command: 'pip install agent-reach' },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'mcporter', label: 'mcporter', usedBy: '(预留:Exa MCP 后端)',
|
|
48
|
+
installs: [
|
|
49
|
+
{ installer: 'npm', command: 'npm i -g mcporter' },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
// opencli and playwright are NOT listed here: they are bundled (plugin-local
|
|
53
|
+
// node_modules, with global reuse fallback) in the dsh-browser plugin, which
|
|
54
|
+
// this plugin injects via the `browser` service.
|
|
55
|
+
];
|
|
56
|
+
/** Resolve a command on PATH (win32: where.exe; posix: sh -c command -v). */
|
|
57
|
+
async function resolveCmd(cmd) {
|
|
58
|
+
const res = await runCli(IS_WIN ? 'where' : 'sh', IS_WIN ? [cmd] : ['-c', 'command -v ' + cmd], { timeoutMs: 8_000, signal: undefined, maxOutput: 64 * 1024 });
|
|
59
|
+
if (res.code !== 0)
|
|
60
|
+
return { found: false };
|
|
61
|
+
const first = res.stdout.split(/\r?\n/).find(line => line.trim().length > 0);
|
|
62
|
+
return first ? { found: true, path: first.trim() } : { found: false };
|
|
63
|
+
}
|
|
64
|
+
/** Detect all backends. */
|
|
65
|
+
export async function detectDeps() {
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const dep of DEPS) {
|
|
68
|
+
const resolved = await resolveCmd(dep.id);
|
|
69
|
+
out.push({ ...dep, available: resolved.found, ...resolved.path ? { path: resolved.path } : {} });
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/** Run the install command for one backend + installer. */
|
|
74
|
+
export async function installDep(id, installer) {
|
|
75
|
+
const dep = DEPS.find(d => d.id === id);
|
|
76
|
+
if (!dep)
|
|
77
|
+
throw new Error('unknown dependency: ' + id);
|
|
78
|
+
const target = dep.installs.find(i => i.installer === installer);
|
|
79
|
+
if (!target)
|
|
80
|
+
throw new Error('unknown installer ' + installer + ' for ' + id + '; try: ' + dep.installs.map(i => i.installer).join(', '));
|
|
81
|
+
return runCompound(target.command, 180_000);
|
|
82
|
+
}
|
|
83
|
+
async function runCompound(command, timeoutMs) {
|
|
84
|
+
// Split on spaces is fine for these fixed commands; quotes are not used.
|
|
85
|
+
const parts = command.split(' ').filter(Boolean);
|
|
86
|
+
const bin = parts.shift();
|
|
87
|
+
return runCli(bin, parts, { timeoutMs, signal: undefined, maxOutput: 256 * 1024 });
|
|
88
|
+
}
|
|
89
|
+
export const DEP_IDS = DEPS.map(d => d.id);
|
|
90
|
+
//# sourceMappingURL=deps.js.map
|
package/lib/deps.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"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"}
|