aura-argus 0.0.0-stage → 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/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +325 -2
- package/RESULTS.md +114 -0
- package/SECURITY.md +47 -0
- package/adapters/dsh/index.mjs +83 -0
- package/docs/integrations/README.md +43 -0
- package/docs/integrations/claude-desktop.md +34 -0
- package/docs/integrations/codex.md +43 -0
- package/docs/integrations/cursor.md +32 -0
- package/docs/integrations/dsh.md +34 -0
- package/docs/integrations/generic-cli.md +44 -0
- package/docs/integrations/generic-http.md +38 -0
- package/docs/integrations/hermes.md +44 -0
- package/docs/integrations/zcode-skill.md +33 -0
- package/docs/integrations/zcode.md +60 -0
- package/openapi.json +244 -0
- package/package.json +49 -4
- package/schema/tools.json +110 -0
- package/src/cli.mjs +177 -0
- package/src/core.mjs +11 -0
- package/src/lib/cache.mjs +78 -0
- package/src/lib/doctor.mjs +27 -0
- package/src/lib/errors.mjs +42 -0
- package/src/lib/extract.mjs +75 -0
- package/src/lib/fallback.mjs +91 -0
- package/src/lib/fetch.mjs +258 -0
- package/src/lib/mcp.mjs +130 -0
- package/src/lib/paths.mjs +22 -0
- package/src/lib/registry.mjs +95 -0
- package/src/lib/router.mjs +252 -0
- package/src/lib/server.mjs +143 -0
- package/src/lib/text.mjs +80 -0
- package/src/registry.json +268 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — 2026-10-21
|
|
4
|
+
|
|
5
|
+
Initial public beta.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Keyless source router: 18 entities / 34 official sources, with aliases and CN→EN term expansion.
|
|
10
|
+
- Evidence contract: per-source passages, scores, URLs, `mode`, attempts, `tookMs`, `cached`.
|
|
11
|
+
- CLI: `search`, `fetch`, `sources`, `doctor`, `serve`, `mcp`; JSON output and typed exit codes.
|
|
12
|
+
- HTTP server: `/health`, `/sources`, `/search`, `/search/batch`, `/fetch`.
|
|
13
|
+
- MCP stdio server: `search`, `search_batch`, `fetch`, `sources`; protocol negotiation and
|
|
14
|
+
client-agnostic `instructions`.
|
|
15
|
+
- Node library exports: `search`, `searchBatch`, `fetchDocument`, `listEntities`, `matchEntity`,
|
|
16
|
+
`registryVersion`, `ArgusError`, `CODES`, `toErrorPayload`, `version`.
|
|
17
|
+
- DSH provider adapter (`adapters/dsh`) and an optional MCP server entry.
|
|
18
|
+
- Batch search with bounded concurrency (1–8), page cache, in-flight de-duplication, and a batch
|
|
19
|
+
budget (MCP 35 s, HTTP 45 s).
|
|
20
|
+
- Retry policy: up to 3 attempts per source for network errors, timeouts, 408/425/429/5xx;
|
|
21
|
+
exponential backoff with jitter; `Retry-After` support; total budget.
|
|
22
|
+
- `ALL_SOURCES_FAILED` error with per-source attempts (CLI exit 4, HTTP 502, MCP `isError`, DSH
|
|
23
|
+
provider error).
|
|
24
|
+
- SSRF protection: private/loopback/link-local/metadata targets denied by default; DNS and
|
|
25
|
+
redirect re-checks; `--allow-private` opt-in.
|
|
26
|
+
- `schema/tools.json` for function-calling agents and `openapi.json` for HTTP integrations.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- The 360/Sogou web fallback is now **opt-in** (`--fallback` / `fallback: true`). Registry-only is
|
|
31
|
+
the default; unregistered questions return `mode: "none"`.
|
|
32
|
+
- MCP instructions and tool descriptions are client-agnostic (no DSH-specific tool names).
|
|
33
|
+
|
|
34
|
+
### Known limitations
|
|
35
|
+
|
|
36
|
+
- Coverage is the registry. Unregistered entities return no evidence unless fallback is enabled.
|
|
37
|
+
- No JavaScript rendering, login walls, CAPTCHA solving, or proxy pools.
|
|
38
|
+
- Single-entity routing; multi-entity questions are not composed.
|
|
39
|
+
- DNS rebinding and proxy environments are documented limitations (see `SECURITY.md`).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aura
|
|
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/README.md
CHANGED
|
@@ -1,3 +1,326 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AuraArgus
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
给 agent 的检索层。两个能力,替代传统的 search 与 fetch:
|
|
4
|
+
|
|
5
|
+
- **search**:把问题路由到注册的官方源,抓回页面,返回**可引用的逐字段落**。
|
|
6
|
+
- **fetch**:取回一个 URL,转成干净的 Markdown 文本。
|
|
7
|
+
|
|
8
|
+
零 API key、零按次计费、默认只连官方页;Windows / macOS / Linux 同一份代码。
|
|
9
|
+
|
|
10
|
+
## 为什么不是搜索引擎聚合器
|
|
11
|
+
|
|
12
|
+
在大陆无代理的实测里,keyless SERP 的召回已经坏了:Bing 对无 cookie 请求返回首词/词典/导航式结果,百度约 30 次请求后跳验证码,DDG / Google 不可达。而**官方页本身可达,正文里就有答案**——失败的是 URL 发现,不是网络。
|
|
13
|
+
|
|
14
|
+
所以 AuraArgus 不聚合 SERP。它维护一份「实体 → 官方源」注册表,把问题路由到正确的官方页,再抽段、给出处。先看一组 6 题的对照实验:
|
|
15
|
+
|
|
16
|
+
| 方案 | 命中 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| keyless 链接列表 | 3 / 12 |
|
|
19
|
+
| keyless + 本地选段 | 4 / 12 |
|
|
20
|
+
| 官方 Search API(付费) | 11 / 12 |
|
|
21
|
+
| **AuraArgus** | **13 / 13** |
|
|
22
|
+
|
|
23
|
+
覆盖评测(18 个实体、中英文、别名、未知实体)是 **31 题 / 141 项硬检查全部通过**;2 项 soft 兜底默认关闭(fallback 改为 opt-in),见 [RESULTS.md](RESULTS.md)。
|
|
24
|
+
|
|
25
|
+
细节见 [RESULTS.md](RESULTS.md) 与 [POSITIONING.md](POSITIONING.md)。
|
|
26
|
+
|
|
27
|
+
## 要求
|
|
28
|
+
|
|
29
|
+
- Node.js **≥ 20**(用到内置 `fetch` / `AbortSignal.timeout`)
|
|
30
|
+
- 零依赖,不需要 `npm install`
|
|
31
|
+
- Windows / macOS / Linux
|
|
32
|
+
|
|
33
|
+
## 安装
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm i -g aura-argus
|
|
37
|
+
aura-argus version
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
或者直接从源码跑:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone <repo> && cd aura-argus
|
|
44
|
+
node src/cli.mjs search "SearXNG 对 429 的冷却时间是多少秒?"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 四种入口
|
|
48
|
+
|
|
49
|
+
### 1. CLI
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# 检索:返回证据(JSON)
|
|
53
|
+
aura-argus search "SearXNG 对 429 的冷却时间是多少秒?"
|
|
54
|
+
|
|
55
|
+
# 人眼可读
|
|
56
|
+
aura-argus search "Tavily 一个 credit 多少钱?" --text
|
|
57
|
+
|
|
58
|
+
# 取回一页:干净 Markdown
|
|
59
|
+
aura-argus fetch https://docs.searxng.org/dev/search_api.html --max-chars 4000
|
|
60
|
+
|
|
61
|
+
# 注册表与健康检查
|
|
62
|
+
aura-argus sources
|
|
63
|
+
aura-argus doctor
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
退出码:`0` 成功、`2` 无证据、`3` 参数错误、`4` 抓取失败、`130` 中断。
|
|
67
|
+
|
|
68
|
+
### 2. 本地 HTTP(任何语言 / agent)
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
aura-argus serve --port 8787
|
|
72
|
+
# {"ok":true,"url":"http://127.0.0.1:8787"}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| 方法 | 路径 | 说明 |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| GET | `/health` | 版本、源数量、uptime |
|
|
78
|
+
| GET | `/sources` | 注册表 |
|
|
79
|
+
| GET | `/search?q=&maxSources=` | 证据包 |
|
|
80
|
+
| POST | `/search` | `{ "question": "...", "maxSources": 3 }` |
|
|
81
|
+
| POST | `/search/batch` | `{ "questions": ["..."], "concurrency": 3 }` |
|
|
82
|
+
| GET | `/fetch?url=&maxChars=` | 页面文本 |
|
|
83
|
+
| POST | `/fetch` | `{ "url": "...", "maxChars": 20000 }` |
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
curl -s 'http://127.0.0.1:8787/search?q=SearXNG+429' | head -c 400
|
|
87
|
+
curl -s 'http://127.0.0.1:8787/fetch?url=https%3A%2F%2Fdocs.searxng.org%2Fdev%2Fsearch_api.html'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
默认只绑 `127.0.0.1`;`--token <t>` 后要求 `Authorization: Bearer <t>`。
|
|
91
|
+
|
|
92
|
+
### 3. MCP stdio(任何 MCP 客户端)
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
aura-argus mcp
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
客户端配置(以 Claude Desktop / 任意 MCP host 为例):
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"aura-argus": {
|
|
104
|
+
"command": "npx",
|
|
105
|
+
"args": ["-y", "aura-argus", "mcp"]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
工具:`search(question, maxSources?)`、`search_batch(questions, concurrency?)`、`fetch(url, maxChars?)`、`sources()`。stdout 只写 JSON-RPC,不混日志。
|
|
112
|
+
|
|
113
|
+
### 4. DSH(DeepSeek Harness)
|
|
114
|
+
|
|
115
|
+
仓库自带 `adapters/dsh/index.mjs`。在 `~/.dsh/profiles/web/cordis.patch.yml` 里插入适配器,并把 web 的 provider 指过去:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
- insert:
|
|
119
|
+
- id: web-argus
|
|
120
|
+
name: 'E:/workspaces/aura-argus/adapters/dsh/index.mjs' # 换成你的 checkout 路径
|
|
121
|
+
config:
|
|
122
|
+
maxSources: 3
|
|
123
|
+
maxChars: 20000
|
|
124
|
+
# marker: true # 验证期打开:snippet 会以 [aura-argus] 开头
|
|
125
|
+
|
|
126
|
+
- id: web
|
|
127
|
+
name: '@deepseek-ai/dsh-web'
|
|
128
|
+
config:
|
|
129
|
+
searchProvider: aura-argus
|
|
130
|
+
fetchProvider: aura-argus-http
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
重启 dsh web 后生效(运行中的进程不会热加载 patch)。验证:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
dsh --profile web --dump-config | Select-String searchProvider # 应显示 aura-argus
|
|
137
|
+
node eval/verify-dsh.mjs --live # 9/9
|
|
138
|
+
aura-argus search "SearXNG 429" --json # 终端侧对照
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
服务端没有 `aura-argus` 时 DSH 会报 `WEB_PROVIDER_CONFIGURED_MISSING`,不会静默回落到计费路径。回滚:删掉 `web-argus` 段,把 `searchProvider` / `fetchProvider` 改回原值(如 `aura-keyless` / `http`),重启。
|
|
142
|
+
|
|
143
|
+
**这替换的是 provider,不是工具。** `web_search` / `web_fetch` 仍是 `tool-web`,受它的契约限制:最多 4 个 query、合并成一个 sources 列表(丢失逐 query 归属)、只给 snippet(我们的 passages 被压成一条)、没有 `search_batch`、fetch 有它的 SSRF/重定向/大小规则。
|
|
144
|
+
|
|
145
|
+
要拿回完整契约,把 AuraArgus 的 MCP server 挂进 DSH(profile patch 里已写入 `mcp-aura-argus`):
|
|
146
|
+
|
|
147
|
+
- 工具:`mcp__aura-argus__search` / `search_batch` / `fetch` / `sources`
|
|
148
|
+
- 想强制走原生工具:给 `tool-web` 加 `disable: true`(先跑一轮确认 MCP 可用,再禁)
|
|
149
|
+
- 内置工具已并发处理 1–4 个 query;MCP 的增量是逐 query 结果、批量上限 20、passages 与出处完整保留
|
|
150
|
+
- MCP 的 `initialize.instructions` 会被 DSH 的 mcp-client 自动注入 systemPrompt(`mcp:aura-argus` 段),工具描述也会作为元数据进入模型——不需要再手写 AGENTS.md 规则
|
|
151
|
+
|
|
152
|
+
### 5. Node 库
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
import { search, searchBatch, fetchDocument } from 'aura-argus';
|
|
156
|
+
|
|
157
|
+
const evidence = await search('SearXNG 对 429 的冷却时间是多少秒?');
|
|
158
|
+
const batch = await searchBatch(['q1', 'q2', 'q3'], { concurrency: 3 });
|
|
159
|
+
const page = await fetchDocument('https://docs.searxng.org/dev/search_api.html', { maxChars: 4000 });
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 契约
|
|
163
|
+
|
|
164
|
+
### search
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"schemaVersion": 1,
|
|
169
|
+
"question": "SearXNG 对 429 的冷却时间是多少秒?",
|
|
170
|
+
"entity": "searxng",
|
|
171
|
+
"mode": "registry",
|
|
172
|
+
"evidence": [
|
|
173
|
+
{
|
|
174
|
+
"url": "https://docs.searxng.org/admin/settings/settings_search.html",
|
|
175
|
+
"title": "search: - SearXNG Documentation",
|
|
176
|
+
"site": "docs.searxng.org",
|
|
177
|
+
"passages": [{ "text": "… suspended_times: … SearxEngineTooManyRequests: 3600 …", "score": 15 }]
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"attempts": [{ "url": "…", "ok": true, "ms": 855, "passages": 6 }],
|
|
181
|
+
"tookMs": 1011,
|
|
182
|
+
"cached": false
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`mode` 取值:`registry`(注册表命中)、`web-fallback`(仅 `--fallback` 时出现的 360/搜狗兜底)、`none`(无证据)。
|
|
187
|
+
|
|
188
|
+
### fetch
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"schemaVersion": 1,
|
|
193
|
+
"url": "https://docs.searxng.org/dev/search_api.html",
|
|
194
|
+
"finalUrl": "https://docs.searxng.org/dev/search_api.html",
|
|
195
|
+
"status": 200,
|
|
196
|
+
"title": "Search API - SearXNG Documentation",
|
|
197
|
+
"text": "# Search API\n\nSearXNG supports querying…",
|
|
198
|
+
"chars": 4000,
|
|
199
|
+
"truncated": true,
|
|
200
|
+
"contentType": "text/html; charset=utf-8",
|
|
201
|
+
"tookMs": 312
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 错误码
|
|
206
|
+
|
|
207
|
+
`BAD_URL`、`BAD_REQUEST`、`PRIVATE_ADDRESS`、`TOO_MANY_REDIRECTS`、`TIMEOUT`、`FETCH_FAILED`、`HTTP_ERROR`、`UNSUPPORTED_CONTENT_TYPE`、`TOO_LARGE`、`NO_ENTITY`、`NO_EVIDENCE`、`ALL_SOURCES_FAILED`。
|
|
208
|
+
|
|
209
|
+
## 源注册表
|
|
210
|
+
|
|
211
|
+
`src/registry.json`:**18 个实体 / 34 个源**,全部在 CN 直连下实测可达(`aura-argus doctor`)。
|
|
212
|
+
|
|
213
|
+
加一个实体:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
"实体": {
|
|
217
|
+
"aliases": ["名字", "别名"],
|
|
218
|
+
"sources": [{ "url": "https://官方页", "title": "…", "covers": ["关键词"] }],
|
|
219
|
+
"discovery": { "type": "sitemap", "url": "https://…/sitemap.xml" }
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
- `covers` 只用于排序;命中实体后默认抓该实体的全部源(上限 `--max-sources`)。
|
|
224
|
+
- 所有源都失败时,若有 `discovery`(`sitemap` 或站点索引),再走一跳发现。
|
|
225
|
+
- 默认 **registry-only**:未注册实体返回 `mode: "none"`;显式 `--fallback`(CLI)/`fallback: true`(HTTP/库)才走 360/搜狗,只返回链接 + 摘要,标 `mode: "web-fallback"`。
|
|
226
|
+
|
|
227
|
+
## 跨平台
|
|
228
|
+
|
|
229
|
+
- 无原生依赖、无 shell 调用、无平台路径写死;只用 `node:` 内置模块。
|
|
230
|
+
- 缓存目录:Windows `%LOCALAPPDATA%\aura-argus\cache`,macOS/Linux `$XDG_CACHE_HOME/aura-argus` 或 `~/.cache/aura-argus`;可用 `AURA_ARGUS_CACHE_DIR` 覆盖。
|
|
231
|
+
- CI 矩阵:`ubuntu / macos / windows × node 20 / 22 / 24`,只跑离线测试与 `npm pack --dry-run`。
|
|
232
|
+
|
|
233
|
+
## 跨 agent
|
|
234
|
+
|
|
235
|
+
MCP stdio 与 CLI 都在本地跑,不绑定 DSH:
|
|
236
|
+
|
|
237
|
+
| agent | 接法 | 实测(2026-10-21) |
|
|
238
|
+
|---|---|---|
|
|
239
|
+
| Codex CLI 0.163 | `codex mcp add aura-argus -- node <abs>/cli.mjs mcp` | `mcp_tool_call` server=`aura-argus` tool=`search`,返回 3600 s + 官方 URL |
|
|
240
|
+
| Hermes 0.21.3 | `hermes mcp add aura-argus --command node --args <abs>/cli.mjs mcp` | 4 tools discovered(1937 ms);`-z` 明确走 MCP,返回 3600 s + URL |
|
|
241
|
+
| ZCode(Electron) | `~/.zcode/cli/config.json` → `mcp.servers`(stdio) | 配置已加;当前 ZCode 进程早于配置,重启后才会拉起 MCP;CLI/skill 仍作兜底 |
|
|
242
|
+
| Claude Desktop / Cursor / Cline | 标准 stdio:`npx -y aura-argus mcp` | 发布后用 MCP Inspector + 各客户端补测 |
|
|
243
|
+
|
|
244
|
+
- Windows 下部分客户端要写 `cmd /c npx ...`;配置路径随客户端不同。
|
|
245
|
+
- 任何能跑 shell 的 agent:`aura-argus search "<q>" --json`。
|
|
246
|
+
|
|
247
|
+
## 失败与重试
|
|
248
|
+
|
|
249
|
+
- `fetchRaw`:每个源最多 3 次尝试(`retries=2`),只重试网络错误、超时、408/425/429/5xx;其余 4xx 立即失败。
|
|
250
|
+
- 退避:300 ms 起、指数 + 抖动,单次最多 3 s;尊重 `Retry-After`(上限 3 s);总预算 `max(20 s, 2×timeout)`,到点即停。
|
|
251
|
+
- 一次检索里所有源都失败 → 结果带 `error.code = ALL_SOURCES_FAILED` 和逐源 `attempts`(含 `tries`、`status`):
|
|
252
|
+
- CLI 退出码 `4`;HTTP `/search` 返回 `502`;MCP `isError: true`;DSH provider 抛 `WEB_PROVIDER_ERROR`。
|
|
253
|
+
- 批量有 budget:MCP 35 s、HTTP 45 s(CLI `--budget`),超时项标 `BATCH_BUDGET_EXCEEDED`,避免重试把一次工具调用拖过客户端 60 s 超时。
|
|
254
|
+
- 不做跨源的二次重试、不做失败缓存/冷却;失败的下一次调用会重新尝试。
|
|
255
|
+
|
|
256
|
+
## 安全边界
|
|
257
|
+
|
|
258
|
+
- 默认拒绝 loopback / 私有网段 / link-local / 组播 / metadata:`127/8`、`10/8`、`172.16/12`、`192.168/16`、`169.254/16`、`::1`、`fc00::/7`、`fe80::/10` 等;DNS 解析后复查,重定向逐跳复检。
|
|
259
|
+
- 显式 opt-in:CLI `--allow-private`,库 `allowPrivate: true`,HTTP `serve --allow-private`,MCP 启动时 `AURA_ARGUS_ALLOW_PRIVATE=1`。
|
|
260
|
+
- 不绕登录/付费墙/验证码;无内置 key、无代理池、无遥测。
|
|
261
|
+
- `serve` 默认绑 `127.0.0.1`;对外暴露时加 `--token`。
|
|
262
|
+
|
|
263
|
+
## 边界
|
|
264
|
+
|
|
265
|
+
- **覆盖率 = 注册表**。没收录的实体默认返回无证据;显式开启 fallback 才走网页兜底。
|
|
266
|
+
- 不做 JS 渲染、不登登录墙、不绕验证码、不做代理池。
|
|
267
|
+
- 低频、单机、只读抓取;对目标站点友好是最低要求。
|
|
268
|
+
- 返回证据,不生成答案;答案由调用方的模型写。
|
|
269
|
+
- `web-fallback` 是 opt-in,依赖 360/搜狗,可能被反爬;失败时明确报 `mode: "none"`。
|
|
270
|
+
|
|
271
|
+
## 性能
|
|
272
|
+
|
|
273
|
+
`npm run bench`(30 题,无缓存冷启动):
|
|
274
|
+
|
|
275
|
+
| 模式 | 总耗时 | 平均 |
|
|
276
|
+
|---|---|---|
|
|
277
|
+
| 串行 | 21.6 s | 721 ms/题 |
|
|
278
|
+
| 批量(concurrency=3,冷) | 6.9 s | 230 ms/题 |
|
|
279
|
+
| 批量(缓存填充) | 6.1 s | 202 ms/题 |
|
|
280
|
+
| 批量(缓存命中) | ~1 ms | — |
|
|
281
|
+
|
|
282
|
+
- **并发可调**:同一批 30 题,c=6 / c=8 实测约 3.5 s / 2.0 s(无空结果);默认 3 是为了对官方站点礼貌,不是性能上限。
|
|
283
|
+
- **同题多源并行**:一个问题的 2–3 个官方源同时抓,不再串行等待。
|
|
284
|
+
- **页面缓存 + in-flight 去重**:批内同一 URL 只抓一次;TTL 10 min。
|
|
285
|
+
- **结果缓存**:同一 query 15 min 内直接命中(`--no-cache` 关闭)。
|
|
286
|
+
|
|
287
|
+
批量入口:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
echo '["q1","q2"]' | aura-argus search --batch [--concurrency 3] [--budget 45000]
|
|
291
|
+
curl -X POST localhost:8787/search/batch -d '{"questions":["q1","q2"]}'
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## 测试与评测
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
npm test # 离线:51 个测试(解析 / 选段 / 注册表 / 缓存 / 批量 / 重试 / 私网拦截 / HTTP / MCP / DSH 适配器)
|
|
298
|
+
npm run eval # 联网:31 题 / 141 项硬检查(+2 项 soft 兜底默认关闭)
|
|
299
|
+
npm run verify # 联网:34 个源的可用性
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## 文件
|
|
303
|
+
|
|
304
|
+
| 路径 | 作用 |
|
|
305
|
+
|---|---|
|
|
306
|
+
| `src/cli.mjs` | CLI 入口 |
|
|
307
|
+
| `src/core.mjs` | 公共 API |
|
|
308
|
+
| `src/registry.json` | 实体 → 官方源(产品资产) |
|
|
309
|
+
| `src/lib/router.mjs` | 实体匹配 → 抓取 → 选段 → 兜底 |
|
|
310
|
+
| `src/lib/fetch.mjs` | URL 校验 / 限时 / 限大小 / 文档转换 |
|
|
311
|
+
| `src/lib/extract.mjs` | 打分 + 邻行窗口 + 表格/列表块合并 |
|
|
312
|
+
| `src/lib/server.mjs` | HTTP 服务 |
|
|
313
|
+
| `src/lib/mcp.mjs` | MCP stdio |
|
|
314
|
+
| `src/lib/cache.mjs` | 内存 + 磁盘缓存 |
|
|
315
|
+
| `eval/` | 金标准问题、评测脚本、注册表检查 |
|
|
316
|
+
| `test/` | 离线测试 |
|
|
317
|
+
| `docs/integrations/` | Codex / Hermes / ZCode / Claude / Cursor / CLI / HTTP 接法 |
|
|
318
|
+
| `schema/tools.json` | OpenAI / Anthropic function-calling 工具 schema |
|
|
319
|
+
| `openapi.json` | HTTP API 的 OpenAPI 3.1 |
|
|
320
|
+
| `SECURITY.md` | 安全模型、私网拦截、漏洞上报 |
|
|
321
|
+
| `adapters/dsh/` | DSH provider 适配器 |
|
|
322
|
+
| `POSITIONING.md` | 定位、市场对比、实验记录 |
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
MIT
|
package/RESULTS.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# 结果(2026-10-21)
|
|
2
|
+
|
|
3
|
+
环境:大陆直连、Clash 关闭(出口 `123.139.x`)。全部请求只到官方页;无 key、无 SERP、无代理、无按次计费。
|
|
4
|
+
|
|
5
|
+
## 评测
|
|
6
|
+
|
|
7
|
+
### 覆盖评测(31 题 / 141 项)
|
|
8
|
+
|
|
9
|
+
`npm run eval`:**141 / 141 项硬检查全部通过**(另 2 项 soft:网页兜底)。覆盖 18 个实体、中英文、别名、未知实体;总耗时 **27.8 s**(无缓存、串行),证据 77,646 字符;单题最长 2.8 s。fallback 改为 opt-in 后,soft 的 2 项默认关闭;实测 360 跳 captcha、搜狗 403,0/2 不计入发布 gate。
|
|
10
|
+
|
|
11
|
+
| 类别 | 题数 | 结果 |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| 注册实体事实(18 个实体) | 24 | 全过 |
|
|
14
|
+
| 别名(深度求索 / nodejs / golang / k8s / 必应) | 5 | 全过 |
|
|
15
|
+
| 未知实体(fallback off) | 1 | `entity:null` / `mode:none` |
|
|
16
|
+
| 网页兜底(soft) | 1 | opt-in;本次 0/2(360 跳 captcha、搜狗 403) |
|
|
17
|
+
|
|
18
|
+
### 对照实验(6 题,A/B/C/D)
|
|
19
|
+
|
|
20
|
+
| 方案 | 材料 | 命中 |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| A · keyless 链接 | 10 条标题 + 摘要 | 3 / 12 |
|
|
23
|
+
| B · keyless + 本地选段 | 逐字段落 | 4 / 12 |
|
|
24
|
+
| C · 官方 Search API | 官方结果 | 11 / 12 |
|
|
25
|
+
| **D · AuraArgus** | 官方源逐字段落 | **13 / 13** |
|
|
26
|
+
|
|
27
|
+
## 失败与重试(2026-10-21)
|
|
28
|
+
|
|
29
|
+
- `fetchRaw`:最多 3 次尝试;重试网络错误、超时、408/425/429/5xx,其余 4xx 不重试。
|
|
30
|
+
- 退避 300 ms 起、指数 + 抖动;尊重 `Retry-After`(上限 3 s);总预算 `max(20 s, 2×timeout)`。
|
|
31
|
+
- 所有源失败:`error.code = ALL_SOURCES_FAILED` + 逐源 `attempts`(`tries` / `status`);CLI 退出 4、HTTP 502、MCP `isError`、DSH provider 抛 `WEB_PROVIDER_ERROR`。
|
|
32
|
+
- 一次全失败测试(mock fetch):2 个源各 3 次尝试,结果正确标记,耗时约 1.6 s。
|
|
33
|
+
- 批量 budget:MCP 35 s、HTTP 45 s;超时项标 `BATCH_BUDGET_EXCEEDED`,防止重试把一次工具调用拖过客户端 60 s 超时。
|
|
34
|
+
|
|
35
|
+
## 安全边界(2026-10-21)
|
|
36
|
+
|
|
37
|
+
- 默认拒绝 loopback / 私有网段 / link-local / 组播 / metadata;DNS 解析后复查,重定向逐跳复检。
|
|
38
|
+
- opt-in:CLI `--allow-private`、HTTP `serve --allow-private`、库 `allowPrivate: true`、MCP `AURA_ARGUS_ALLOW_PRIVATE=1`。
|
|
39
|
+
- 不绕登录/付费墙/验证码;无 key、无代理池、无遥测。
|
|
40
|
+
- `serve` 默认绑 `127.0.0.1`,对外暴露需 `--token`。
|
|
41
|
+
|
|
42
|
+
## 性能(`npm run bench`,30 题)
|
|
43
|
+
|
|
44
|
+
| 模式 | 总耗时 | 平均 |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| 串行(冷) | 21.62 s | 721 ms/题 |
|
|
47
|
+
| 批量 c=3(冷) | **6.89 s** | 230 ms/题 |
|
|
48
|
+
| 批量 c=3(缓存填充) | 6.05 s | 202 ms/题 |
|
|
49
|
+
| 批量 c=3(缓存命中) | ~1 ms | — |
|
|
50
|
+
|
|
51
|
+
冷启动批量 **3.14×**;命中结果缓存后 <10 ms。证据数量在三种模式下一致(49 条来源),说明并行/缓存没有改变结果。
|
|
52
|
+
|
|
53
|
+
并发上限 8:同一批 30 题在 **c=6 / c=8 下约 3.5 s / 2.0 s**(单独实测,仍无空结果);默认 c=3 是礼貌值,不是性能上限。
|
|
54
|
+
|
|
55
|
+
## 注册表
|
|
56
|
+
|
|
57
|
+
`npm run verify`:**18 个实体 / 34 个源**,全部 200。
|
|
58
|
+
|
|
59
|
+
覆盖:DeepSeek、SearXNG、Tavily、Google CSE、Bing、Python、Node.js(http/fs)、GitHub(REST/Actions)、MDN、React、Vue、Rust、Go、Docker、PostgreSQL、nginx、Kubernetes、Redis。
|
|
60
|
+
|
|
61
|
+
## 测试
|
|
62
|
+
|
|
63
|
+
`npm test`:**51 / 51** 通过(解析、块合并、选段、URL 校验、注册表结构、别名、缓存 TTL/磁盘往返、批量、重试/全失败、私网拦截/重定向复检、HTTP 服务、MCP 握手/协议协商/解析错误、DSH 适配器映射)。
|
|
64
|
+
|
|
65
|
+
`npm run verify-dsh`:静态 **8/8**;`--live` **9/9**(含真检索)。DSH patch 已指向 `aura-argus` / `aura-argus-http`。
|
|
66
|
+
|
|
67
|
+
## 打包与安装(2026-10-21)
|
|
68
|
+
|
|
69
|
+
- `npm pack`:**34 files / 41.6 KB compressed / 126.6 KB unpacked**;含 `docs/integrations/`、`schema/tools.json`、`openapi.json`、`SECURITY.md`、`CHANGELOG.md`。
|
|
70
|
+
- tarball 安装到临时 prefix:`aura-argus version` → `0.1.0`;MCP initialize/tools-list → 4 tools + `instructions`。
|
|
71
|
+
- 安装目录清理后无进程/端口残留(仅按需 `serve`)。
|
|
72
|
+
|
|
73
|
+
## 跨 agent(2026-10-21)
|
|
74
|
+
|
|
75
|
+
| agent | 版本 | 接法 | 实测 |
|
|
76
|
+
|---|---|---|---|
|
|
77
|
+
| Codex CLI | 0.163.0-alpha.10.2 | `codex mcp add aura-argus -- node .../cli.mjs mcp` | `mcp_tool_call` server=`aura-argus` tool=`search`,返回 3600 s + 官方 URL |
|
|
78
|
+
| Hermes | 0.21.3 | `hermes mcp add aura-argus --command node --args .../cli.mjs mcp` | 4 tools discovered(首测 1937 ms;新代码复测 3656 ms,通用描述);`hermes -z` 走 MCP,返回 3600 s + URL |
|
|
79
|
+
| ZCode | Electron | `~/.zcode/cli/config.json` → `mcp.servers`(stdio,`type:"stdio"`) | 配置已加;当前进程早于配置,重启后验证;CLI/skill 兜底 |
|
|
80
|
+
|
|
81
|
+
## DSH 运行态(2026-10-21 重启后)
|
|
82
|
+
|
|
83
|
+
- `dsh --profile web --dump-config` → `searchProvider: aura-argus` / `fetchProvider: aura-argus-http`
|
|
84
|
+
- `web_search "SearXNG 对 429 的冷却时间是多少秒?"` → 来源 `docs.searxng.org`,snippet 是 600 字符的逐字段落(含 `formats : - html`),不是普通 SERP 摘要
|
|
85
|
+
- `web_fetch https://docs.searxng.org/dev/search_api.html` → Markdown(`# Search API`,无导航条)
|
|
86
|
+
- `node eval/verify-dsh.mjs --live` → 9/9(含 MCP server 插入检查)
|
|
87
|
+
- MCP server 的 `initialize.instructions` 会被 `dsh-mcp-client` 注入 systemPrompt(`mcp:aura-argus`),工具描述也会作为元数据进入模型;`search_batch` 上限 20
|
|
88
|
+
|
|
89
|
+
> 注:上面的 DSH 运行态是 20:41 那次重启的结果。22:xx 之后又改了 SSRF 默认拒绝、fallback 默认 opt-in、MCP 通用工具描述;**当前 DSH 进程仍是旧代码**,下次重启才加载。Codex/Hermes 每次调用重新拉起 MCP,已用新代码复测(Codex 无异常;Hermes 3656 ms / 4 tools)。
|
|
90
|
+
|
|
91
|
+
## 交付形态
|
|
92
|
+
|
|
93
|
+
| 入口 | 命令 / 用法 |
|
|
94
|
+
|---|---|
|
|
95
|
+
| CLI | `aura-argus search …` / `fetch` / `sources` / `doctor` / `serve` / `mcp` |
|
|
96
|
+
| HTTP | `aura-argus serve --port 8787`(`/health` `/sources` `/search` `/search/batch` `/fetch`;`openapi.json`) |
|
|
97
|
+
| MCP stdio | `aura-argus mcp`(tools: search / search_batch / fetch / sources) |
|
|
98
|
+
| Node 库 | `import { search, searchBatch, fetchDocument } from 'aura-argus'` |
|
|
99
|
+
| DSH | `adapters/dsh/index.mjs` + profile patch(`searchProvider: aura-argus` / `fetchProvider: aura-argus-http`) |
|
|
100
|
+
|
|
101
|
+
## 这张表不能读出的四件事
|
|
102
|
+
|
|
103
|
+
1. **覆盖率是天花板。** 31 题覆盖 18 个实体;没收录的实体默认返回无证据,显式 `--fallback` 才走 360/搜狗。
|
|
104
|
+
2. **检查的是「事实是否出现在证据里」**,不是「agent 答得对」。C 的 QPS 错误(把 100 答成 5)说明官方索引也会选错源;证据段落 + 出处让调用方能核对。
|
|
105
|
+
3. **registry 是手工资产。** 价值在数据(实体 → 官方源),不在算法;维护成本和覆盖范围是后续工程。
|
|
106
|
+
4. **Google 走了 `.cn` 镜像。** 不是所有被墙的官方源都有镜像。
|
|
107
|
+
|
|
108
|
+
## 复跑
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npm test
|
|
112
|
+
npm run eval
|
|
113
|
+
npm run verify
|
|
114
|
+
```
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
`0.1.x` is the current public beta line. Security fixes land on the latest `0.1.x`.
|
|
6
|
+
|
|
7
|
+
## Reporting
|
|
8
|
+
|
|
9
|
+
Use GitHub private vulnerability reporting (Security → Report a vulnerability) at
|
|
10
|
+
<https://github.com/Ck-epsilon/aura-argus/security/advisories/new>. If that is unavailable,
|
|
11
|
+
open an issue that describes the impact without including a working exploit or secrets.
|
|
12
|
+
|
|
13
|
+
Please include: affected version, command/tool, expected vs actual behavior, and whether the
|
|
14
|
+
target is local, private-network, or public. We aim to acknowledge within 7 days.
|
|
15
|
+
|
|
16
|
+
## Security model
|
|
17
|
+
|
|
18
|
+
AuraArgus is a local, read-only retrieval tool. It does not host a service, does not require an
|
|
19
|
+
API key, and does not send telemetry.
|
|
20
|
+
|
|
21
|
+
- **Network egress is user-initiated.** `search` only fetches URLs from the local registry (or an
|
|
22
|
+
explicitly discovered source); `fetch` accepts a URL from the caller.
|
|
23
|
+
- **Private targets are denied by default.** Loopback, RFC1918, CGNAT, link-local, multicast,
|
|
24
|
+
documentation ranges, cloud metadata addresses, `localhost`, `fc00::/7`, `fe80::/10`, `::1`,
|
|
25
|
+
and IPv4-mapped private addresses are rejected. DNS is resolved before the request and every
|
|
26
|
+
redirect hop is re-checked.
|
|
27
|
+
- **Opt-in escape hatch.** `--allow-private` / `allowPrivate: true` / `AURA_ARGUS_ALLOW_PRIVATE=1`
|
|
28
|
+
disables the private-target check. Only use it for a trusted local source; prompt injection can
|
|
29
|
+
abuse it if it is enabled by default.
|
|
30
|
+
- **No bypass of access controls.** The tool does not log in, solve CAPTCHAs, bypass paywalls, or
|
|
31
|
+
rotate proxies. Users are responsible for complying with the target site's terms and robots
|
|
32
|
+
policy.
|
|
33
|
+
- **HTTP server is local by default.** `serve` binds `127.0.0.1`. When binding to another host,
|
|
34
|
+
always set `--token`; the token is a bearer secret, not a substitute for network isolation.
|
|
35
|
+
- **Cache is local.** Search results and pages are cached under the user cache directory; use
|
|
36
|
+
`--no-cache` to bypass the result cache.
|
|
37
|
+
|
|
38
|
+
## Known limitations
|
|
39
|
+
|
|
40
|
+
- DNS rebinding is mitigated by pre-resolution checks but not fully eliminated; a hostile DNS
|
|
41
|
+
server could change answers between the check and the request.
|
|
42
|
+
- Node's built-in `fetch` does not honor `HTTP_PROXY` / `HTTPS_PROXY` automatically. Corporate
|
|
43
|
+
networks may need `NODE_EXTRA_CA_CERTS` or a custom dispatcher.
|
|
44
|
+
- The 360/Sogou fallback is opt-in and scrapes public result pages; it is subject to anti-bot
|
|
45
|
+
blocking and may violate a target site's terms if used at scale.
|
|
46
|
+
- `--allow-private` deliberately weakens SSRF protection; it should never be the default in a
|
|
47
|
+
multi-user deployment.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// DSH 适配器:把 AuraArgus 注册成 ctx.web 的 search / fetch provider。
|
|
2
|
+
// 不依赖 DSH 的源码:只用到 ctx.web.registerSearchProvider / registerFetchProvider。
|
|
3
|
+
import { search, fetchDocument, version } from '../../src/core.mjs';
|
|
4
|
+
|
|
5
|
+
export const name = 'aura-argus-dsh';
|
|
6
|
+
export const inject = ['web'];
|
|
7
|
+
export const SEARCH_ID = 'aura-argus';
|
|
8
|
+
export const FETCH_ID = 'aura-argus-http';
|
|
9
|
+
|
|
10
|
+
function providerError(message, code = 'WEB_PROVIDER_ERROR') {
|
|
11
|
+
const error = new Error(message);
|
|
12
|
+
error.code = code;
|
|
13
|
+
return error;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 构建两个 provider。注入 searchImpl/fetchImpl 便于离线测试。
|
|
18
|
+
*/
|
|
19
|
+
export function createProviders({ searchImpl = search, fetchImpl = fetchDocument, config = {} } = {}) {
|
|
20
|
+
const maxSources = Math.max(1, Math.min(6, Number(config.maxSources ?? 3)));
|
|
21
|
+
const maxChars = Math.max(100, Number(config.maxChars ?? 20_000));
|
|
22
|
+
const marker = config.marker === true;
|
|
23
|
+
const allowPrivate = config.allowPrivate === true;
|
|
24
|
+
|
|
25
|
+
const searchProvider = {
|
|
26
|
+
id: SEARCH_ID,
|
|
27
|
+
available() { return true; },
|
|
28
|
+
async search(request, signal) {
|
|
29
|
+
if (signal?.aborted) throw providerError('search aborted', 'WEB_ABORTED');
|
|
30
|
+
const limit = Math.max(1, Math.min(maxSources, Number(request?.maxResults ?? maxSources)));
|
|
31
|
+
try {
|
|
32
|
+
const result = await searchImpl(request.query, { maxSources: limit, cache: config.cache !== false, fallback: config.fallback === true });
|
|
33
|
+
if (result.error) throw providerError(`aura-argus search failed: ${result.error.code} (${result.error.attempts ?? 0} sources)`);
|
|
34
|
+
const sources = (result.evidence || []).map((entry) => {
|
|
35
|
+
const raw = entry.passages?.[0]?.text || '';
|
|
36
|
+
const snippet = marker && raw ? `[aura-argus] ${raw}` : raw;
|
|
37
|
+
return {
|
|
38
|
+
url: entry.url,
|
|
39
|
+
...(entry.title ? { title: entry.title } : {}),
|
|
40
|
+
...(snippet ? { snippet: snippet.slice(0, 600) } : {}),
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
return { sources, truncated: false };
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw providerError(`aura-argus search failed: ${error?.message || error}`);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const fetchProvider = {
|
|
51
|
+
id: FETCH_ID,
|
|
52
|
+
available() { return true; },
|
|
53
|
+
async fetch(request, signal) {
|
|
54
|
+
if (signal?.aborted) throw providerError('fetch aborted', 'WEB_ABORTED');
|
|
55
|
+
try {
|
|
56
|
+
const doc = await fetchImpl(request.url, { maxChars, allowPrivate });
|
|
57
|
+
return {
|
|
58
|
+
url: doc.finalUrl || doc.url,
|
|
59
|
+
statusCode: doc.status,
|
|
60
|
+
body: { kind: 'text', content: doc.text },
|
|
61
|
+
truncated: Boolean(doc.truncated),
|
|
62
|
+
};
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// 与 DSH 的约定一致:非 2xx 是结果,不是异常。
|
|
65
|
+
if (error?.code === 'HTTP_ERROR' && error?.details?.status) {
|
|
66
|
+
return { url: request.url, statusCode: error.details.status, body: { kind: 'text', content: '' }, truncated: false };
|
|
67
|
+
}
|
|
68
|
+
throw providerError(`aura-argus fetch failed: ${error?.message || error}`);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return { searchProvider, fetchProvider };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function apply(ctx, config = {}) {
|
|
77
|
+
const { searchProvider, fetchProvider } = createProviders({ config });
|
|
78
|
+
ctx.web.registerSearchProvider(searchProvider);
|
|
79
|
+
ctx.web.registerFetchProvider(fetchProvider);
|
|
80
|
+
if (config.debug) {
|
|
81
|
+
process.stderr.write(`[aura-argus] registered ${SEARCH_ID} + ${FETCH_ID} (v${version})\n`);
|
|
82
|
+
}
|
|
83
|
+
}
|