dsh-web-search-pro 0.2.0 → 0.2.3
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 +179 -0
- package/README.md +197 -32
- package/assets/skills/dsh-web-search-pro/SKILL.md +14 -13
- package/assets/skills/dsh-web-search-pro/references/config.md +36 -0
- package/assets/skills/dsh-web-search-pro/references/sources.md +19 -4
- package/assets/skills/dsh-web-search-pro/references/troubleshooting.md +3 -1
- package/catalog/sources.v1.json +22 -12
- package/lib/actions/approval.js +50 -1
- package/lib/actions/approval.js.map +1 -1
- package/lib/actions/config.js +274 -0
- package/lib/actions/config.js.map +1 -0
- package/lib/actions/errors.js +8 -1
- package/lib/actions/errors.js.map +1 -1
- package/lib/actions/format.js +10 -0
- package/lib/actions/format.js.map +1 -1
- package/lib/actions/index-view.js +2 -2
- package/lib/actions/index-view.js.map +1 -1
- package/lib/actions/read.js +7 -3
- package/lib/actions/read.js.map +1 -1
- package/lib/actions/registry.js +3 -1
- package/lib/actions/registry.js.map +1 -1
- package/lib/actions/run.js +2 -2
- package/lib/actions/run.js.map +1 -1
- package/lib/actions/schema.js +18 -0
- package/lib/actions/schema.js.map +1 -1
- package/lib/actions/search.js +12 -6
- package/lib/actions/search.js.map +1 -1
- package/lib/actions/sources.js +116 -41
- package/lib/actions/sources.js.map +1 -1
- package/lib/actions/types.js +19 -1
- package/lib/actions/types.js.map +1 -1
- package/lib/browser-access.js +25 -0
- package/lib/browser-access.js.map +1 -1
- package/lib/catalog/recommend.js +11 -3
- package/lib/catalog/recommend.js.map +1 -1
- package/lib/catalog/schema.js +3 -1
- package/lib/catalog/schema.js.map +1 -1
- package/lib/cli/builtin-specs.js +341 -0
- package/lib/cli/builtin-specs.js.map +1 -0
- package/lib/cli/chain.js +193 -0
- package/lib/cli/chain.js.map +1 -0
- package/lib/cli/chains-spec.js +118 -0
- package/lib/cli/chains-spec.js.map +1 -0
- package/lib/cli/engine.js +99 -0
- package/lib/cli/engine.js.map +1 -0
- package/lib/cli/opencli-sites.js +83 -0
- package/lib/cli/opencli-sites.js.map +1 -0
- package/lib/cli/opencli.js +153 -0
- package/lib/cli/opencli.js.map +1 -0
- package/lib/cli/probe.js +128 -0
- package/lib/cli/probe.js.map +1 -0
- package/lib/cli/runner.js +564 -0
- package/lib/cli/runner.js.map +1 -0
- package/lib/cli/spec.js +496 -0
- package/lib/cli/spec.js.map +1 -0
- package/lib/cli/time-text.js +79 -0
- package/lib/cli/time-text.js.map +1 -0
- package/lib/cli/trial.js +57 -0
- package/lib/cli/trial.js.map +1 -0
- package/lib/client/SettingsCard.js +14 -32
- package/lib/client/SettingsCard.js.map +1 -1
- package/lib/client/agent-mark.js +27 -0
- package/lib/client/agent-mark.js.map +1 -0
- package/lib/client/card-frame.js +118 -0
- package/lib/client/card-frame.js.map +1 -0
- package/lib/client/cli-form.js +257 -0
- package/lib/client/cli-form.js.map +1 -0
- package/lib/client/field-docs.js +130 -0
- package/lib/client/field-docs.js.map +1 -0
- package/lib/client/field-keys.js +81 -0
- package/lib/client/field-keys.js.map +1 -0
- package/lib/client/field-rows.js +71 -0
- package/lib/client/field-rows.js.map +1 -0
- package/lib/client/fill.js +3 -0
- package/lib/client/fill.js.map +1 -0
- package/lib/client/form-specs.js +15 -1
- package/lib/client/form-specs.js.map +1 -1
- package/lib/client/form.js +296 -27
- package/lib/client/form.js.map +1 -1
- package/lib/client/group-advanced.js +23 -0
- package/lib/client/group-advanced.js.map +1 -0
- package/lib/client/group-agent.js +28 -0
- package/lib/client/group-agent.js.map +1 -0
- package/lib/client/group-cli.js +136 -0
- package/lib/client/group-cli.js.map +1 -0
- package/lib/client/group-common.js +29 -0
- package/lib/client/group-common.js.map +1 -0
- package/lib/client/group-judge.js +67 -0
- package/lib/client/group-judge.js.map +1 -0
- package/lib/client/group-order.js +201 -0
- package/lib/client/group-order.js.map +1 -0
- package/lib/client/group-runtime.js +33 -0
- package/lib/client/group-runtime.js.map +1 -0
- package/lib/client/group-sources.js +83 -0
- package/lib/client/group-sources.js.map +1 -0
- package/lib/client/groups-basic.js +36 -0
- package/lib/client/groups-basic.js.map +1 -0
- package/lib/client/index.js.map +1 -1
- package/lib/client/json-list.js +50 -0
- package/lib/client/json-list.js.map +1 -0
- package/lib/client/locales.js +666 -215
- package/lib/client/locales.js.map +1 -1
- package/lib/client/order.js +192 -0
- package/lib/client/order.js.map +1 -0
- package/lib/client/overlay-ops.js +46 -0
- package/lib/client/overlay-ops.js.map +1 -0
- package/lib/client/sources-table.js +1 -0
- package/lib/client/sources-table.js.map +1 -1
- package/lib/client/styles.js +74 -47
- package/lib/client/styles.js.map +1 -1
- package/lib/client/text-view.js +98 -0
- package/lib/client/text-view.js.map +1 -0
- package/lib/client/ui-kit.js +120 -0
- package/lib/client/ui-kit.js.map +1 -0
- package/lib/client/validators.js +22 -0
- package/lib/client/validators.js.map +1 -1
- package/lib/client.js +9151 -1987
- package/lib/client.js.map +1 -1
- package/lib/config-fillers.js +53 -0
- package/lib/config-fillers.js.map +1 -0
- package/lib/config-groups.js +49 -0
- package/lib/config-groups.js.map +1 -0
- package/lib/config.js +87 -107
- package/lib/config.js.map +1 -1
- package/lib/default-chain.js +66 -0
- package/lib/default-chain.js.map +1 -0
- package/lib/deps.js +109 -102
- package/lib/deps.js.map +1 -1
- package/lib/engine-error.js +19 -0
- package/lib/engine-error.js.map +1 -0
- package/lib/engines.js +32 -115
- package/lib/engines.js.map +1 -1
- package/lib/fetch.js +23 -4
- package/lib/fetch.js.map +1 -1
- package/lib/index.js +30 -5
- package/lib/index.js.map +1 -1
- package/lib/overlay-types.js +88 -0
- package/lib/overlay-types.js.map +1 -0
- package/lib/overlay.js +683 -0
- package/lib/overlay.js.map +1 -0
- package/lib/pipeline/candidates.js +27 -1
- package/lib/pipeline/candidates.js.map +1 -1
- package/lib/pipeline/compile.js +63 -0
- package/lib/pipeline/compile.js.map +1 -1
- package/lib/pipeline/confidence.js +64 -0
- package/lib/pipeline/confidence.js.map +1 -0
- package/lib/pipeline/fusion.js +50 -3
- package/lib/pipeline/fusion.js.map +1 -1
- package/lib/pipeline/plan.js +2 -2
- package/lib/pipeline/plan.js.map +1 -1
- package/lib/pipeline/render.js +20 -2
- package/lib/pipeline/render.js.map +1 -1
- package/lib/pipeline/run.js +21 -7
- package/lib/pipeline/run.js.map +1 -1
- package/lib/pipeline/sources-spec.js +19 -3
- package/lib/pipeline/sources-spec.js.map +1 -1
- package/lib/providers/builtin.js +13 -14
- package/lib/providers/builtin.js.map +1 -1
- package/lib/providers/deepseek.js +348 -0
- package/lib/providers/deepseek.js.map +1 -0
- package/lib/providers/http.js.map +1 -1
- package/lib/providers/keyed-meta.js +7 -0
- package/lib/providers/keyed-meta.js.map +1 -1
- package/lib/providers/platforms.js +118 -58
- package/lib/providers/platforms.js.map +1 -1
- package/lib/providers/registry.js.map +1 -1
- package/lib/restart.js +47 -0
- package/lib/restart.js.map +1 -0
- package/lib/router.js +203 -27
- package/lib/router.js.map +1 -1
- package/lib/rpc-types.js +15 -0
- package/lib/rpc-types.js.map +1 -0
- package/lib/rpc.js +85 -0
- package/lib/rpc.js.map +1 -0
- package/lib/tools.js +10 -4
- package/lib/tools.js.map +1 -1
- package/lib/types/actions/approval.d.ts +11 -0
- package/lib/types/actions/config.d.ts +54 -0
- package/lib/types/actions/format.d.ts +9 -2
- package/lib/types/actions/run.d.ts +1 -0
- package/lib/types/actions/schema.d.ts +7 -1
- package/lib/types/actions/sources.d.ts +29 -3
- package/lib/types/actions/types.d.ts +28 -2
- package/lib/types/browser-access.d.ts +17 -0
- package/lib/types/catalog/recommend.d.ts +4 -0
- package/lib/types/catalog/schema.d.ts +2 -0
- package/lib/types/cli/builtin-specs.d.ts +38 -0
- package/lib/types/cli/chain.d.ts +83 -0
- package/lib/types/cli/chains-spec.d.ts +48 -0
- package/lib/types/cli/engine.d.ts +50 -0
- package/lib/types/cli/opencli-sites.d.ts +24 -0
- package/lib/types/cli/opencli.d.ts +77 -0
- package/lib/types/cli/probe.d.ts +53 -0
- package/lib/types/cli/runner.d.ts +126 -0
- package/lib/types/cli/spec.d.ts +269 -0
- package/lib/types/cli/time-text.d.ts +12 -0
- package/lib/types/cli/trial.d.ts +19 -0
- package/lib/types/client/SettingsCard.d.ts +17 -1
- package/lib/types/client/agent-mark.d.ts +22 -0
- package/lib/types/client/card-frame.d.ts +35 -0
- package/lib/types/client/cli-form.d.ts +97 -0
- package/lib/types/client/field-docs.d.ts +15 -0
- package/lib/types/client/field-keys.d.ts +41 -0
- package/lib/types/client/field-rows.d.ts +70 -0
- package/lib/types/client/fill.d.ts +2 -0
- package/lib/types/client/form-specs.d.ts +12 -3
- package/lib/types/client/form.d.ts +79 -1
- package/lib/types/client/group-advanced.d.ts +9 -0
- package/lib/types/client/group-agent.d.ts +20 -0
- package/lib/types/client/group-cli.d.ts +52 -0
- package/lib/types/client/group-common.d.ts +12 -0
- package/lib/types/client/group-judge.d.ts +17 -0
- package/lib/types/client/group-order.d.ts +26 -0
- package/lib/types/client/group-runtime.d.ts +15 -0
- package/lib/types/client/group-sources.d.ts +46 -0
- package/lib/types/client/groups-basic.d.ts +18 -0
- package/lib/types/client/index.d.ts +8 -0
- package/lib/types/client/json-list.d.ts +21 -0
- package/lib/types/client/locales.d.ts +1079 -196
- package/lib/types/client/order.d.ts +102 -0
- package/lib/types/client/overlay-ops.d.ts +37 -0
- package/lib/types/client/styles.d.ts +56 -41
- package/lib/types/client/text-view.d.ts +22 -0
- package/lib/types/client/ui-kit.d.ts +200 -0
- package/lib/types/client/validators.d.ts +6 -0
- package/lib/types/config-fillers.d.ts +9 -0
- package/lib/types/config-groups.d.ts +23 -0
- package/lib/types/config.d.ts +265 -216
- package/lib/types/default-chain.d.ts +63 -0
- package/lib/types/deps.d.ts +25 -23
- package/lib/types/engine-error.d.ts +12 -0
- package/lib/types/engines.d.ts +45 -10
- package/lib/types/fetch.d.ts +12 -3
- package/lib/types/index.d.ts +164 -146
- package/lib/types/overlay-types.d.ts +98 -0
- package/lib/types/overlay.d.ts +141 -0
- package/lib/types/pipeline/candidates.d.ts +19 -0
- package/lib/types/pipeline/compile.d.ts +11 -0
- package/lib/types/pipeline/confidence.d.ts +35 -0
- package/lib/types/pipeline/fusion.d.ts +23 -1
- package/lib/types/pipeline/render.d.ts +16 -0
- package/lib/types/pipeline/run.d.ts +3 -1
- package/lib/types/pipeline/sources-spec.d.ts +5 -2
- package/lib/types/pipeline/types.d.ts +37 -0
- package/lib/types/providers/deepseek.d.ts +130 -0
- package/lib/types/providers/http.d.ts +2 -1
- package/lib/types/providers/keyed-meta.d.ts +5 -0
- package/lib/types/providers/platforms.d.ts +15 -3
- package/lib/types/providers/registry.d.ts +10 -0
- package/lib/types/restart.d.ts +52 -0
- package/lib/types/router.d.ts +69 -9
- package/lib/types/rpc-types.d.ts +79 -0
- package/lib/types/rpc.d.ts +41 -0
- package/lib/types/tools.d.ts +6 -0
- package/lib/types/util.d.ts +16 -1
- package/lib/util.js +17 -4
- package/lib/util.js.map +1 -1
- package/package.json +51 -43
- package/scripts/check-client-bundle.mjs +1 -1
- package/scripts/cli-login-check.mjs +214 -0
- package/lib/client/RubricEditor.js +0 -47
- package/lib/client/RubricEditor.js.map +0 -1
- package/lib/client/fields.js +0 -31
- package/lib/client/fields.js.map +0 -1
- package/lib/types/client/RubricEditor.d.ts +0 -6
- package/lib/types/client/fields.d.ts +0 -65
package/lib/deps.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependency detection and install for the CLI/platform backends.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* Backends shell out to tools installed outside DSH: the built-in CLI adapter specs (bili, yt-dlp, twitter, xhs, zhihu,
|
|
4
|
+
* rdt, omnireach, gh, wx-search-cli, tanso, the standalone opencli) plus the user's own `cliAdapters`, and mcporter. This
|
|
5
|
+
* module reports which are present, whether the command on PATH really has the contract the adapter needs (a same-named
|
|
6
|
+
* program with another contract is `incompatible`, never `detected`), and how to install them; the sources.deps /
|
|
7
|
+
* sources.install actions expose it to the model. Probes are local, cached with a TTL, and never run a search or a login.
|
|
8
8
|
*
|
|
9
9
|
* Install is intentionally a MODEL-FACING TOOL, not a browser settings button:
|
|
10
10
|
* a browser button running winget/pip/npm would be arbitrary command execution
|
|
@@ -13,50 +13,53 @@
|
|
|
13
13
|
* @module web-search-pro/deps
|
|
14
14
|
*/
|
|
15
15
|
import { runCli } from "./util.js";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
{ installer: '
|
|
23
|
-
{ installer: '
|
|
16
|
+
import { BILI_CLI_INSTALLS, BILI_CLI_REVISION, BILI_CLI_SOURCE, BILI_CLI_VERSION, BUILTIN_CLI_SPECS, TWITTER_CLI_INSTALLS, builtinSpecById } from "./cli/builtin-specs.js";
|
|
17
|
+
import { OPENCLI_PROBE } from "./cli/opencli.js";
|
|
18
|
+
import { evaluateCliContract, findOnPath, probeAll } from "./cli/probe.js";
|
|
19
|
+
import { resolveCliAdapters } from "./cli/spec.js";
|
|
20
|
+
export { BILI_CLI_INSTALLS, BILI_CLI_REVISION, BILI_CLI_SOURCE, BILI_CLI_VERSION, TWITTER_CLI_INSTALLS };
|
|
21
|
+
const py = (pkg) => [
|
|
22
|
+
{ installer: 'uv', command: 'uv tool install ' + pkg },
|
|
23
|
+
{ installer: 'pipx', command: 'pipx install ' + pkg },
|
|
24
|
+
{ installer: 'pip', command: 'pip install ' + pkg },
|
|
24
25
|
];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
26
|
+
/** Install commands of the spec-backed CLIs (a user-defined adapter has none: it names its own package in packageNote). */
|
|
27
|
+
const SPEC_INSTALLS = {
|
|
28
|
+
bili: BILI_CLI_INSTALLS,
|
|
29
|
+
'yt-dlp': [{ installer: 'uv', command: 'uv tool install yt-dlp' }, { installer: 'pip', command: 'pip install yt-dlp' }],
|
|
30
|
+
twitter: TWITTER_CLI_INSTALLS,
|
|
31
|
+
xhs: py('xiaohongshu-cli'),
|
|
32
|
+
zhihu: py('pyzhihu-cli'),
|
|
33
|
+
rdt: py('git+https://github.com/public-clis/rdt-cli'),
|
|
34
|
+
omnireach: py('omnireach'),
|
|
35
|
+
gh: [{ installer: 'brew', command: 'brew install gh' }, { installer: 'winget', command: 'winget install GitHub.cli' }],
|
|
36
|
+
'wx-search-cli': [{ installer: 'npm', command: 'npm i -g wx-search-cli' }],
|
|
37
|
+
tanso: [{ installer: 'npm', command: 'npm i -g @geekjourneyx/tanso' }],
|
|
38
|
+
opencli: [{ installer: 'npm', command: 'npm i -g @jackwener/opencli' }],
|
|
39
|
+
};
|
|
40
|
+
const USED_BY = {
|
|
41
|
+
bili: 'bilibili 平台后端',
|
|
42
|
+
'yt-dlp': 'youtube 平台后端',
|
|
43
|
+
twitter: 'twitter 平台后端(第一后端,执行 `twitter search --json`;另需 TWITTER_AUTH_TOKEN 与 TWITTER_CT0,放在 DSH 凭据或宿主进程环境里)',
|
|
44
|
+
xhs: 'xiaohongshu 平台后端(只读 `xhs search`;需用户自行 `xhs login`)',
|
|
45
|
+
zhihu: 'zhihu 平台后端(只读 `zhihu search`;需用户自行 `zhihu login`)',
|
|
46
|
+
rdt: 'reddit 平台后端(只读 `rdt search`;需用户自行 `rdt login`)',
|
|
47
|
+
omnireach: 'wechat 平台后端与 omnireach 多源平台(只读 `omnireach search`)',
|
|
48
|
+
gh: 'github / github-issues / github-code 的 gh 回退后端(只读 `gh search`;需用户自行 `gh auth login`)',
|
|
49
|
+
'wx-search-cli': 'wechat 平台第二后端(只读 `wx-search-cli search`;按上游文档,未实测)',
|
|
50
|
+
tanso: 'tanso 平台后端(只读;按上游文档,未实测)',
|
|
51
|
+
opencli: '独立 OpenCLI:xiaohongshu / reddit / twitter 等站点的搜索后端(按 `opencli list` 的 search 命令,使用用户自己的 Chrome)',
|
|
52
|
+
};
|
|
53
|
+
const LABELS = {
|
|
54
|
+
bili: 'bili-cli', 'yt-dlp': 'yt-dlp', twitter: 'twitter-cli', xhs: 'xhs (xiaohongshu-cli)', zhihu: 'zhihu-cli', rdt: 'rdt-cli', omnireach: 'OmniReach', gh: 'GitHub CLI',
|
|
55
|
+
'wx-search-cli': 'wx-search-cli', tanso: 'Tanso', opencli: 'OpenCLI (standalone)',
|
|
56
|
+
};
|
|
35
57
|
/** Validate the public-clis bili command rather than trusting an ambiguous package name. */
|
|
36
58
|
export function evaluateBiliCli(versionOutput, searchHelpOutput) {
|
|
37
|
-
const
|
|
38
|
-
if (
|
|
39
|
-
return { available:
|
|
40
|
-
|
|
41
|
-
return { available: false, version, diagnostic: `bili ${version} is older than required ${BILI_CLI_VERSION}` };
|
|
42
|
-
}
|
|
43
|
-
const missing = ['--type', '--max', '--json'].filter(option => !searchHelpOutput.includes(option));
|
|
44
|
-
if (missing.length) {
|
|
45
|
-
return { available: false, version, diagnostic: `bili search contract missing ${missing.join(', ')}` };
|
|
46
|
-
}
|
|
47
|
-
return { available: true, version };
|
|
48
|
-
}
|
|
49
|
-
async function probeBiliCli(bin) {
|
|
50
|
-
const env = { PYTHONUTF8: '1', PYTHONIOENCODING: 'utf-8' };
|
|
51
|
-
const version = await runCli(bin, ['--version'], { timeoutMs: 8_000, signal: undefined, env, maxOutput: 64 * 1024 });
|
|
52
|
-
if (version.code !== 0) {
|
|
53
|
-
return { available: false, diagnostic: `bili --version failed with exit ${version.code}` };
|
|
54
|
-
}
|
|
55
|
-
const help = await runCli(bin, ['search', '--help'], { timeoutMs: 8_000, signal: undefined, env, maxOutput: 128 * 1024 });
|
|
56
|
-
if (help.code !== 0) {
|
|
57
|
-
return { available: false, diagnostic: `bili search --help failed with exit ${help.code}` };
|
|
58
|
-
}
|
|
59
|
-
return evaluateBiliCli(version.stdout + version.stderr, help.stdout + help.stderr);
|
|
59
|
+
const verdict = evaluateCliContract(builtinSpecById('bili'), 'bili', { code: 0, output: versionOutput }, { code: 0, output: searchHelpOutput });
|
|
60
|
+
if (verdict.state === 'detected')
|
|
61
|
+
return { available: true, ...verdict.version ? { version: verdict.version } : {} };
|
|
62
|
+
return { available: false, ...verdict.version ? { version: verdict.version } : {}, diagnostic: (verdict.reason ?? '').replace(/ \(a different program with the same name\?\)$/, '') };
|
|
60
63
|
}
|
|
61
64
|
/**
|
|
62
65
|
* The twitter backend runs `twitter search <query> -n N` (twitter-cli). Another program that happens to be
|
|
@@ -69,37 +72,8 @@ export function evaluateTwitterCli(searchHelpOutput, exitCode) {
|
|
|
69
72
|
return { available: false, diagnostic: 'twitter search --help does not describe a search command (not twitter-cli?)' };
|
|
70
73
|
return { available: true };
|
|
71
74
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return evaluateTwitterCli(help.stdout + help.stderr, help.code);
|
|
75
|
-
}
|
|
76
|
-
export const TWITTER_CLI_INSTALLS = [
|
|
77
|
-
{ installer: 'uv', command: 'uv tool install twitter-cli' },
|
|
78
|
-
{ installer: 'pipx', command: 'pipx install twitter-cli' },
|
|
79
|
-
{ installer: 'pip', command: 'pip install twitter-cli' },
|
|
80
|
-
];
|
|
81
|
-
/** One external tool the plugin may shell out to. */
|
|
82
|
-
const DEPS = [
|
|
83
|
-
{
|
|
84
|
-
id: 'bili', label: 'bili-cli', usedBy: 'bilibili 后端',
|
|
85
|
-
source: `public-clis/bilibili-cli v${BILI_CLI_VERSION} (${BILI_CLI_REVISION.slice(0, 12)})`,
|
|
86
|
-
requiredVersion: `>=${BILI_CLI_VERSION}`,
|
|
87
|
-
installs: BILI_CLI_INSTALLS,
|
|
88
|
-
probe: probeBiliCli,
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
id: 'yt-dlp', label: 'yt-dlp', usedBy: 'youtube 后端',
|
|
92
|
-
installs: [
|
|
93
|
-
{ installer: 'uv', command: 'uv tool install yt-dlp' },
|
|
94
|
-
{ installer: 'pip', command: 'pip install yt-dlp' },
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
id: 'twitter', label: 'twitter-cli', usedBy: 'twitter 平台后端(agentreach-twitter,执行 `twitter search`;另需 TWITTER_AUTH_TOKEN 与 TWITTER_CT0)',
|
|
99
|
-
source: 'twitter-cli (PyPI twitter-cli; command `twitter`)',
|
|
100
|
-
installs: TWITTER_CLI_INSTALLS,
|
|
101
|
-
probe: probeTwitterCli,
|
|
102
|
-
},
|
|
75
|
+
/** Non-spec tools: Exa's MCP fallback and the optional Agent-Reach installer helper. */
|
|
76
|
+
const EXTRA_DEPS = [
|
|
103
77
|
{
|
|
104
78
|
id: 'agent-reach', label: 'Agent-Reach', usedBy: '安装助手(可顺带装 twitter-cli 等渠道;本插件不直接执行它,twitter 搜索看 twitter 项)',
|
|
105
79
|
optional: true,
|
|
@@ -114,36 +88,60 @@ const DEPS = [
|
|
|
114
88
|
{ installer: 'npm', command: 'npm i -g mcporter' },
|
|
115
89
|
],
|
|
116
90
|
},
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
91
|
+
// playwright is NOT listed here: it is bundled in the dsh-browser plugin, which this plugin uses optionally via the
|
|
92
|
+
// `browser` service. The dsh-browser OpenCLI is a backend of the platform chains, not a CLI of this list; the
|
|
93
|
+
// standalone `opencli` below is the user's own install.
|
|
120
94
|
];
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
95
|
+
const infoOf = (subject, spec, usedBy, label, installs) => ({
|
|
96
|
+
id: subject.id,
|
|
97
|
+
label,
|
|
98
|
+
usedBy,
|
|
99
|
+
source: subject.packageNote,
|
|
100
|
+
...subject.probe.minVersion ? { requiredVersion: '>=' + subject.probe.minVersion } : {},
|
|
101
|
+
...spec?.verification ? { verification: spec.verification.status } : {},
|
|
102
|
+
installs,
|
|
103
|
+
});
|
|
104
|
+
/** The built-in specs (one entry per CLI; a CLI serving several platforms is one entry) and the standalone opencli. */
|
|
105
|
+
function builtinDeps() {
|
|
106
|
+
const out = BUILTIN_CLI_SPECS.map(spec => ({ subject: spec, info: infoOf(spec, spec, USED_BY[spec.id] ?? spec.platforms.join(' / ') + ' 后端', LABELS[spec.id] ?? spec.bins[0], SPEC_INSTALLS[spec.id] ?? []) }));
|
|
107
|
+
out.push({ subject: OPENCLI_PROBE, info: { ...infoOf(OPENCLI_PROBE, undefined, USED_BY.opencli, LABELS.opencli, SPEC_INSTALLS.opencli), verification: 'contract-only' } });
|
|
108
|
+
return out;
|
|
128
109
|
}
|
|
129
|
-
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
110
|
+
/** Order the plugin has always listed them in, then the new adapters, then the user's. */
|
|
111
|
+
const ORDER = ['bili', 'yt-dlp', 'twitter', 'agent-reach', 'mcporter'];
|
|
112
|
+
export const DEP_IDS = [...new Set([...ORDER, ...BUILTIN_CLI_SPECS.map(s => s.id), 'opencli', ...EXTRA_DEPS.map(d => d.id)])];
|
|
113
|
+
/** Detect every dependency: the spec-backed CLIs through their cached contract probes, the rest by presence on PATH. */
|
|
114
|
+
export async function detectDeps(options = {}) {
|
|
115
|
+
const specs = builtinDeps();
|
|
116
|
+
const user = resolveCliAdapters(options.config?.cliAdapters).specs;
|
|
117
|
+
const userDeps = [...user].map(([id, spec]) => ({
|
|
118
|
+
subject: { ...spec, id: 'custom-cli:' + id },
|
|
119
|
+
info: { id: 'custom-cli:' + id, label: spec.bins[0] + ' (自定义)', usedBy: 'custom-cli:' + id + ' 平台后端(用户定义,未验证)', source: spec.packageNote, ...spec.probe.minVersion ? { requiredVersion: '>=' + spec.probe.minVersion } : {}, installs: [] },
|
|
120
|
+
}));
|
|
121
|
+
const all = [...specs, ...userDeps];
|
|
122
|
+
const probes = await probeAll(all.map(a => a.subject), { ...options.force ? { force: true } : {} });
|
|
123
|
+
const found = new Map();
|
|
124
|
+
for (const { subject, info } of all) {
|
|
125
|
+
const probe = probes.get(subject.id);
|
|
126
|
+
found.set(subject.id, {
|
|
127
|
+
...info,
|
|
128
|
+
available: probe.state === 'detected',
|
|
129
|
+
installation: probe.state,
|
|
130
|
+
...probe.path ? { path: probe.path } : {},
|
|
131
|
+
...probe.version ? { version: probe.version } : {},
|
|
132
|
+
...probe.state === 'incompatible' && probe.reason ? { diagnostic: probe.reason } : {},
|
|
133
|
+
});
|
|
141
134
|
}
|
|
142
|
-
|
|
135
|
+
for (const extra of EXTRA_DEPS) {
|
|
136
|
+
const path = findOnPath(extra.id);
|
|
137
|
+
found.set(extra.id, { ...extra, available: !!path, installation: path ? 'detected' : 'missing', ...path ? { path } : {} });
|
|
138
|
+
}
|
|
139
|
+
const order = [...ORDER, ...BUILTIN_CLI_SPECS.map(s => s.id), 'opencli', ...EXTRA_DEPS.map(d => d.id), ...userDeps.map(d => d.info.id)];
|
|
140
|
+
return [...new Set(order)].map(id => found.get(id)).filter((d) => d !== undefined);
|
|
143
141
|
}
|
|
144
142
|
/** Run the install command for one backend + installer. */
|
|
145
143
|
export async function installDep(id, installer) {
|
|
146
|
-
const dep =
|
|
144
|
+
const dep = [...builtinDeps().map(b => ({ id: b.info.id, installs: b.info.installs })), ...EXTRA_DEPS].find(d => d.id === id);
|
|
147
145
|
if (!dep)
|
|
148
146
|
throw new Error('unknown dependency: ' + id);
|
|
149
147
|
const target = dep.installs.find(i => i.installer === installer);
|
|
@@ -157,5 +155,14 @@ async function runCompound(command, timeoutMs) {
|
|
|
157
155
|
const bin = parts.shift();
|
|
158
156
|
return runCli(bin, parts, { timeoutMs, signal: undefined, maxOutput: 256 * 1024 });
|
|
159
157
|
}
|
|
160
|
-
|
|
158
|
+
/** The installer `sources.install` uses when none is named: the first one listed for the dependency. */
|
|
159
|
+
export function defaultInstaller(id) {
|
|
160
|
+
const dep = [...builtinDeps().map(b => ({ id: b.info.id, installs: b.info.installs })), ...EXTRA_DEPS].find(d => d.id === id);
|
|
161
|
+
if (!dep)
|
|
162
|
+
throw new Error('unknown backend: ' + id + ' (sources.deps lists them: ' + DEP_IDS.join(', ') + ')');
|
|
163
|
+
const first = dep.installs[0];
|
|
164
|
+
if (!first)
|
|
165
|
+
throw new Error(id + ' has no install command here: see its source in sources.deps');
|
|
166
|
+
return first.installer;
|
|
167
|
+
}
|
|
161
168
|
//# sourceMappingURL=deps.js.map
|
package/lib/deps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error every search engine and CLI adapter throws. Leaf module (no imports), so both engines.ts and the CLI adapter
|
|
3
|
+
* layer can extend it without an import cycle.
|
|
4
|
+
* @module web-search-pro/engine-error
|
|
5
|
+
*/
|
|
6
|
+
export class EngineError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
retryable;
|
|
9
|
+
retryAfterMs;
|
|
10
|
+
/** `retryAfterMs`: the service's own wait hint (Retry-After); the router uses it as the cooldown. */
|
|
11
|
+
constructor(message, code, retryable = true, retryAfterMs) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.retryable = retryable;
|
|
15
|
+
this.retryAfterMs = retryAfterMs;
|
|
16
|
+
this.name = 'EngineError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=engine-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-error.js","sourceRoot":"","sources":["../src/engine-error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAEE;IAAuB;IAA2B;IADxF,qGAAqG;IACrG,YAAY,OAAe,EAAW,IAAY,EAAW,YAAY,IAAI,EAAW,YAAqB;QAC3G,KAAK,CAAC,OAAO,CAAC,CAAA;QADsB,SAAI,GAAJ,IAAI,CAAQ;QAAW,cAAS,GAAT,SAAS,CAAO;QAAW,iBAAY,GAAZ,YAAY,CAAS;QAE3G,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;IAC3B,CAAC;CACF"}
|
package/lib/engines.js
CHANGED
|
@@ -8,19 +8,11 @@ import { httpGet, runCli, jsYaml, stripTags, capText, decodeRedirectUrl } from "
|
|
|
8
8
|
import { browserGap, requireBrowser } from "./browser-access.js";
|
|
9
9
|
import { PLATFORM_SEARCH_SPECS, parseCookieString } from "./platform-search.js";
|
|
10
10
|
import { ExaClient } from "./exa-client.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
constructor(message, code, retryable = true, retryAfterMs) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.code = code;
|
|
19
|
-
this.retryable = retryable;
|
|
20
|
-
this.retryAfterMs = retryAfterMs;
|
|
21
|
-
this.name = 'EngineError';
|
|
22
|
-
}
|
|
23
|
-
}
|
|
11
|
+
import { EngineError } from "./engine-error.js";
|
|
12
|
+
import { cliSpecEngine, specEnv } from "./cli/engine.js";
|
|
13
|
+
import { builtinSpecById } from "./cli/builtin-specs.js";
|
|
14
|
+
import { buildArgv, missingEnv, parseCliOutput } from "./cli/runner.js";
|
|
15
|
+
export { EngineError };
|
|
24
16
|
function withTimeout(promise, ms, label) {
|
|
25
17
|
return new Promise((resolve, reject) => {
|
|
26
18
|
const timer = setTimeout(() => reject(new EngineError(label + ' timed out', 'ENGINE_TIMEOUT')), ms);
|
|
@@ -357,58 +349,20 @@ export function githubIssuesEngine(deps) {
|
|
|
357
349
|
},
|
|
358
350
|
};
|
|
359
351
|
}
|
|
360
|
-
// ── Bilibili (bili CLI)
|
|
352
|
+
// ── Bilibili (bili CLI, through the CLI adapter spec) ──────────────────────
|
|
353
|
+
const biliSpec = builtinSpecById('bili');
|
|
354
|
+
const ytDlpSpec = builtinSpecById('yt-dlp');
|
|
355
|
+
const twitterSpec = builtinSpecById('twitter');
|
|
361
356
|
export function bilibiliEngine(deps) {
|
|
362
|
-
return {
|
|
363
|
-
id: 'bilibili',
|
|
364
|
-
label: 'B站 (bili-cli)',
|
|
365
|
-
available: () => deps.enableCli,
|
|
366
|
-
async search(query, count, signal) {
|
|
367
|
-
const res = await runCli('bili', biliSearchArgs(query, count), {
|
|
368
|
-
timeoutMs: 30_000,
|
|
369
|
-
signal,
|
|
370
|
-
outputEncoding: 'utf-8',
|
|
371
|
-
env: { PYTHONUTF8: '1', PYTHONIOENCODING: 'utf-8' },
|
|
372
|
-
});
|
|
373
|
-
if (res.code !== 0)
|
|
374
|
-
throw new EngineError('bili search failed: ' + (res.stderr.trim() || res.stdout.trim() || 'exit ' + res.code).slice(0, 200), 'ENGINE_ERROR');
|
|
375
|
-
return { sources: parseBilibiliSearchOutput(res.stdout) };
|
|
376
|
-
},
|
|
377
|
-
};
|
|
357
|
+
return cliSpecEngine(biliSpec, 'bilibili', deps, { id: 'bilibili', label: 'B站 (bili-cli)' });
|
|
378
358
|
}
|
|
379
|
-
/** Exact argv contract supported by public-clis/bilibili-cli v0.6.2
|
|
359
|
+
/** Exact argv contract supported by public-clis/bilibili-cli v0.6.2+ (the `bili` spec). */
|
|
380
360
|
export function biliSearchArgs(query, count) {
|
|
381
|
-
return
|
|
361
|
+
return buildArgv(biliSpec.search, { query, count });
|
|
382
362
|
}
|
|
383
|
-
/** Parse and validate bili-cli's versioned JSON envelope. */
|
|
363
|
+
/** Parse and validate bili-cli's versioned JSON envelope (the `bili` spec). */
|
|
384
364
|
export function parseBilibiliSearchOutput(output) {
|
|
385
|
-
|
|
386
|
-
try {
|
|
387
|
-
envelope = JSON.parse(output);
|
|
388
|
-
}
|
|
389
|
-
catch {
|
|
390
|
-
throw new EngineError('bili output is not valid UTF-8 JSON', 'ENGINE_ERROR');
|
|
391
|
-
}
|
|
392
|
-
if (envelope.ok !== true || envelope.schema_version !== '1' || !Array.isArray(envelope.data)) {
|
|
393
|
-
const detail = typeof envelope.message === 'string'
|
|
394
|
-
? envelope.message
|
|
395
|
-
: typeof envelope.error === 'string' ? envelope.error : 'unexpected response envelope';
|
|
396
|
-
throw new EngineError('bili search failed: ' + capText(detail, 200), 'ENGINE_ERROR');
|
|
397
|
-
}
|
|
398
|
-
return envelope.data
|
|
399
|
-
.filter(item => typeof item.bvid === 'string' && item.bvid.length > 0)
|
|
400
|
-
.map(item => {
|
|
401
|
-
const title = typeof item.title === 'string' ? stripTags(item.title) : undefined;
|
|
402
|
-
const author = typeof item.author === 'string' ? item.author : undefined;
|
|
403
|
-
const duration = typeof item.duration === 'string' ? item.duration : undefined;
|
|
404
|
-
const play = typeof item.play === 'number' || typeof item.play === 'string' ? item.play : undefined;
|
|
405
|
-
const meta = [author ? 'UP: ' + author : undefined, play !== undefined ? '播放: ' + play : undefined, duration].filter(Boolean);
|
|
406
|
-
return {
|
|
407
|
-
url: 'https://www.bilibili.com/video/' + item.bvid,
|
|
408
|
-
...title ? { title } : {},
|
|
409
|
-
...meta.length ? { snippet: capText(meta.join(' | '), 300) } : {},
|
|
410
|
-
};
|
|
411
|
-
});
|
|
365
|
+
return parseCliOutput(biliSpec, biliSpec.search, output, 1_000);
|
|
412
366
|
}
|
|
413
367
|
// ── V2EX (sov2ex community search API) ──────────────────────────────────────
|
|
414
368
|
export function v2exEngine(allowProxyFakeIp = false) {
|
|
@@ -446,45 +400,13 @@ export function v2exEngine(allowProxyFakeIp = false) {
|
|
|
446
400
|
},
|
|
447
401
|
};
|
|
448
402
|
}
|
|
449
|
-
// ── YouTube (yt-dlp search)
|
|
403
|
+
// ── YouTube (yt-dlp search, through the CLI adapter spec) ───────────────────
|
|
450
404
|
export function youtubeEngine(deps, cli = runCli) {
|
|
451
|
-
return {
|
|
452
|
-
id: 'youtube',
|
|
453
|
-
label: 'YouTube (yt-dlp)',
|
|
454
|
-
available: () => deps.enableCli,
|
|
455
|
-
async search(query, count, signal) {
|
|
456
|
-
const n = Math.min(count, 10);
|
|
457
|
-
const res = await cli('yt-dlp', ['ytsearch' + n + ':' + query, '--flat-playlist', '--skip-download', '--no-warnings', '--print', '%(id)s\t%(title)s\t%(channel)s\t%(view_count)s\t%(duration_string)s'], { timeoutMs: 60_000, signal, outputEncoding: 'utf-8' });
|
|
458
|
-
if (res.code !== 0)
|
|
459
|
-
throw new EngineError('yt-dlp failed: ' + (res.stderr.trim() || res.stdout.trim() || 'exit ' + res.code).slice(0, 200), 'ENGINE_ERROR');
|
|
460
|
-
const sources = [];
|
|
461
|
-
for (const line of res.stdout.split(/\r?\n/)) {
|
|
462
|
-
const [id, title, channel, views, duration] = line.split('\t');
|
|
463
|
-
if (!id || !title)
|
|
464
|
-
continue;
|
|
465
|
-
const meta = [];
|
|
466
|
-
if (channel)
|
|
467
|
-
meta.push(channel);
|
|
468
|
-
if (views && views !== 'None')
|
|
469
|
-
meta.push(views + ' views');
|
|
470
|
-
if (duration)
|
|
471
|
-
meta.push(duration);
|
|
472
|
-
sources.push({
|
|
473
|
-
url: 'https://www.youtube.com/watch?v=' + id,
|
|
474
|
-
title,
|
|
475
|
-
...meta.length ? { snippet: meta.join(' | ') } : {},
|
|
476
|
-
});
|
|
477
|
-
if (sources.length >= n)
|
|
478
|
-
break;
|
|
479
|
-
}
|
|
480
|
-
if (!sources.length)
|
|
481
|
-
throw new EngineError('yt-dlp returned no results', 'ENGINE_EMPTY', true);
|
|
482
|
-
return { sources };
|
|
483
|
-
},
|
|
484
|
-
};
|
|
405
|
+
return cliSpecEngine(ytDlpSpec, 'youtube', deps, { id: 'youtube', label: 'YouTube (yt-dlp)', ...cli !== runCli ? { run: cli } : {} });
|
|
485
406
|
}
|
|
486
407
|
// ── OpenCLI platform search (reuses the user's logged-in browser session) ───
|
|
487
|
-
|
|
408
|
+
/** Platforms the dsh-browser OpenCLI bridge has a site adapter for (platform -> adapter name). */
|
|
409
|
+
export const OPENCLI_PLATFORMS = {
|
|
488
410
|
xiaohongshu: 'xiaohongshu',
|
|
489
411
|
twitter: 'twitter',
|
|
490
412
|
reddit: 'reddit',
|
|
@@ -530,31 +452,26 @@ export function opencliEngine(platform, deps) {
|
|
|
530
452
|
};
|
|
531
453
|
}
|
|
532
454
|
// ── agent-reach CLI backends (twitter etc.) ─────────────────────────────────
|
|
455
|
+
/**
|
|
456
|
+
* The legacy `agentreach-twitter` engine, now a thin view of the `twitter` CLI spec (the platform chain uses the spec
|
|
457
|
+
* directly; this keeps the old engine id and its install message). Credentials are checked by `available()`.
|
|
458
|
+
*/
|
|
533
459
|
export function agentReachEngine(platform, deps) {
|
|
534
460
|
if (platform === 'twitter') {
|
|
461
|
+
const leg = cliSpecEngine(twitterSpec, 'twitter', deps, { id: 'agentreach-twitter', label: 'agent-reach twitter-cli', skipCredentialGate: true });
|
|
535
462
|
return {
|
|
536
463
|
id: 'agentreach-twitter',
|
|
537
464
|
label: 'agent-reach twitter-cli',
|
|
538
|
-
available: () => deps.enableCli && deps.agentReachEnabled &&
|
|
539
|
-
async search(query, count, signal) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
for (const line of res.stdout.split(/\r?\n/)) {
|
|
548
|
-
const m = /(https?:\/\/[^\s]+)/.exec(line);
|
|
549
|
-
if (!m)
|
|
550
|
-
continue;
|
|
551
|
-
const title = stripTags(line).replace(m[1], '').trim();
|
|
552
|
-
if (title)
|
|
553
|
-
sources.push({ url: m[1], title: capText(title, 200) });
|
|
554
|
-
if (sources.length >= count)
|
|
555
|
-
break;
|
|
465
|
+
available: () => deps.enableCli && deps.agentReachEnabled && missingEnv(twitterSpec, specEnv(deps)).length === 0,
|
|
466
|
+
async search(query, count, signal, options) {
|
|
467
|
+
try {
|
|
468
|
+
return await leg.search(query, count, signal, options);
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
if (error?.code === 'CLI_NOT_FOUND')
|
|
472
|
+
throw new EngineError('the twitter command could not be started: install twitter-cli (sources.install backend=twitter); Agent-Reach alone does not provide it', 'ENGINE_UNAVAILABLE', false);
|
|
473
|
+
throw error;
|
|
556
474
|
}
|
|
557
|
-
return { sources };
|
|
558
475
|
},
|
|
559
476
|
};
|
|
560
477
|
}
|