argo-search 1.0.1 → 2.9.7

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.
Files changed (463) hide show
  1. package/LICENSE +201 -21
  2. package/README.en.md +822 -0
  3. package/README.es.md +864 -0
  4. package/README.ja.md +864 -0
  5. package/README.ko.md +864 -0
  6. package/README.md +867 -320
  7. package/SKILL.md +135 -0
  8. package/assets/readme/hero.svg +121 -0
  9. package/assets/readme/made-with-beautify.svg +10 -0
  10. package/assets/readme/proof-routes.svg +73 -0
  11. package/assets/readme/settings-keys.png +0 -0
  12. package/assets/readme/settings-tools.png +0 -0
  13. package/assets/readme/why-better.svg +104 -0
  14. package/assets/readme/workflow.svg +83 -0
  15. package/backends/domain_profiles.json +2308 -96
  16. package/backends/engine_registry.yaml +3314 -503
  17. package/backends/query_synonyms_cn.json +35 -0
  18. package/backends/quota_profiles.json +2409 -161
  19. package/backends/source_types_cn.json +83 -0
  20. package/backends/text_lexicon.json +44 -0
  21. package/bin/argo +703 -0
  22. package/bin/argo.js +71 -39
  23. package/config.yaml +4976 -363
  24. package/cordis.patch.yml +21 -0
  25. package/data/countries.json +40 -0
  26. package/data/lang_matrix/lang_capability.json +842 -0
  27. package/data/lang_matrix/matrix_2026-09-10.json +11921 -0
  28. package/data/regions_cn.json +1 -0
  29. package/docs/ADDING_NEW_ENGINE.md +184 -0
  30. package/docs/ARGO_INTRO.md +124 -0
  31. package/docs/DATA_SOURCE_GAPS.md +81 -0
  32. package/docs/DESIGN_LOCAL_DATA_FUSION.md +90 -0
  33. package/docs/ENGINE_CATALOG.md +564 -0
  34. package/docs/MCP_SETUP.md +106 -0
  35. package/docs/PLATFORM_PATHS.md +111 -0
  36. package/docs/RELEASE_NOTES_v2.8.0.md +71 -0
  37. package/docs/RELEASE_NOTES_v2.8.2.md +63 -0
  38. package/docs/RELEASE_NOTES_v2.8.3.md +55 -0
  39. package/docs/RELEASE_NOTES_v2.8.4.md +79 -0
  40. package/docs/RELEASE_NOTES_v2.8.5.md +102 -0
  41. package/docs/RELEASE_NOTES_v2.8.6.md +66 -0
  42. package/docs/RELEASE_NOTES_v2.8.7.md +65 -0
  43. package/docs/RELEASE_NOTES_v2.8.8.md +67 -0
  44. package/docs/RELEASE_NOTES_v2.8.9.md +67 -0
  45. package/docs/RELEASE_NOTES_v2.9.0.md +64 -0
  46. package/docs/SEARCH_ARCHIVE.md +115 -0
  47. package/docs/assets/architecture.svg +104 -0
  48. package/docs/assets/hero.svg +98 -0
  49. package/docs/engines/bangumi.md +27 -0
  50. package/docs/engines/biorxiv.md +27 -0
  51. package/docs/engines/clawhub.md +27 -0
  52. package/docs/engines/crt_sh.md +27 -0
  53. package/docs/engines/datacite.md +27 -0
  54. package/docs/engines/deps_dev.md +27 -0
  55. package/docs/engines/douban_movie.md +27 -0
  56. package/docs/engines/endoflife.md +27 -0
  57. package/docs/engines/flk_law.md +27 -0
  58. package/docs/engines/fxtwitter.md +27 -0
  59. package/docs/engines/google_news.md +27 -0
  60. package/docs/engines/gov_regulations.md +27 -0
  61. package/docs/engines/guqian.md +27 -0
  62. package/docs/engines/hackernews.md +27 -0
  63. package/docs/engines/iplant.md +27 -0
  64. package/docs/engines/keenable.md +27 -0
  65. package/docs/engines/met_museum.md +27 -0
  66. package/docs/engines/nasa_images.md +27 -0
  67. package/docs/engines/netease_music.md +27 -0
  68. package/docs/engines/npm.md +27 -0
  69. package/docs/engines/nvd.md +27 -0
  70. package/docs/engines/openreview.md +27 -0
  71. package/docs/engines/openstd.md +27 -0
  72. package/docs/engines/parallel_free.md +27 -0
  73. package/docs/engines/people_daily.md +27 -0
  74. package/docs/engines/realtime_index.md +27 -0
  75. package/docs/engines/sec_edgar.md +27 -0
  76. package/docs/engines/seltz.md +27 -0
  77. package/docs/engines/skillsmp.md +27 -0
  78. package/docs/engines/sspai.md +27 -0
  79. package/docs/engines/std_samr.md +27 -0
  80. package/docs/engines/train.md +27 -0
  81. package/docs/engines/un_comtrade.md +27 -0
  82. package/docs/engines/wikisource.md +27 -0
  83. package/docs/engines/zdic.md +27 -0
  84. package/docs/engines/zenodo.md +27 -0
  85. package/docs/engines/zhihu_hot_app.md +27 -0
  86. package/docs//344/270/272/344/273/200/344/271/210/351/200/211/346/213/251argo.md +176 -0
  87. package/engines/README.md +10 -0
  88. package/engines/_template_cli.yaml +39 -0
  89. package/engines/_template_http.yaml +37 -0
  90. package/engines/plugins/_template_plugin.py +50 -0
  91. package/engines/specs/_cisa_kev.yaml +54 -0
  92. package/engines/specs/_osv.yaml +63 -0
  93. package/engines/specs/aljazeera.yaml +43 -0
  94. package/engines/specs/antara.yaml +43 -0
  95. package/engines/specs/artic.yaml +20 -0
  96. package/engines/specs/aviation_weather.yaml +39 -0
  97. package/engines/specs/bangumi.yaml +21 -0
  98. package/engines/specs/biorxiv.yaml +24 -0
  99. package/engines/specs/carbon_intensity.yaml +32 -0
  100. package/engines/specs/cinii.yaml +44 -0
  101. package/engines/specs/clawhub.yaml +49 -0
  102. package/engines/specs/cleveland.yaml +19 -0
  103. package/engines/specs/cn_ai_news.yaml +43 -0
  104. package/engines/specs/core.yaml +35 -0
  105. package/engines/specs/crt_sh.yaml +38 -0
  106. package/engines/specs/ct24.yaml +43 -0
  107. package/engines/specs/datacite.yaml +27 -0
  108. package/engines/specs/datagov_uk.yaml +41 -0
  109. package/engines/specs/ddgs_images.yaml +45 -0
  110. package/engines/specs/deepseek_search.yaml +74 -0
  111. package/engines/specs/deezer.yaml +20 -0
  112. package/engines/specs/deps_dev.yaml +21 -0
  113. package/engines/specs/digup.yaml +36 -0
  114. package/engines/specs/doi.yaml +39 -0
  115. package/engines/specs/douban_movie.yaml +22 -0
  116. package/engines/specs/dw_news.yaml +47 -0
  117. package/engines/specs/egov_law.yaml +21 -0
  118. package/engines/specs/elpais.yaml +43 -0
  119. package/engines/specs/endoflife.yaml +21 -0
  120. package/engines/specs/energy_charts.yaml +21 -0
  121. package/engines/specs/factcheck_org.yaml +52 -0
  122. package/engines/specs/faz.yaml +43 -0
  123. package/engines/specs/federal_register.yaml +57 -0
  124. package/engines/specs/firecrawl.yaml +53 -0
  125. package/engines/specs/flk_law.yaml +24 -0
  126. package/engines/specs/folha.yaml +43 -0
  127. package/engines/specs/france24.yaml +44 -0
  128. package/engines/specs/full_fact.yaml +47 -0
  129. package/engines/specs/fxtwitter.yaml +31 -0
  130. package/engines/specs/gbfs_nyc.yaml +32 -0
  131. package/engines/specs/gdacs.yaml +21 -0
  132. package/engines/specs/gdelt.yaml +64 -0
  133. package/engines/specs/google_news.yaml +22 -0
  134. package/engines/specs/gov_regulations.yaml +38 -0
  135. package/engines/specs/guardian_rss.yaml +59 -0
  136. package/engines/specs/hurriyet.yaml +43 -0
  137. package/engines/specs/iplant.yaml +25 -0
  138. package/engines/specs/jikan.yaml +24 -0
  139. package/engines/specs/jolpica.yaml +20 -0
  140. package/engines/specs/k10plus.yaml +20 -0
  141. package/engines/specs/keenable.yaml +44 -0
  142. package/engines/specs/lefigaro.yaml +43 -0
  143. package/engines/specs/listenbrainz.yaml +19 -0
  144. package/engines/specs/matichon.yaml +43 -0
  145. package/engines/specs/met_museum.yaml +21 -0
  146. package/engines/specs/nasa_images.yaml +45 -0
  147. package/engines/specs/netease_music.yaml +38 -0
  148. package/engines/specs/nhk.yaml +43 -0
  149. package/engines/specs/nhtsa_vpic.yaml +20 -0
  150. package/engines/specs/noaa_swpc.yaml +20 -0
  151. package/engines/specs/nvd.yaml +38 -0
  152. package/engines/specs/obis.yaml +20 -0
  153. package/engines/specs/opencitations.yaml +52 -0
  154. package/engines/specs/openf1.yaml +21 -0
  155. package/engines/specs/openfoodfacts.yaml +45 -0
  156. package/engines/specs/openligadb.yaml +20 -0
  157. package/engines/specs/openreview.yaml +37 -0
  158. package/engines/specs/openstd.yaml +21 -0
  159. package/engines/specs/people_daily.yaml +22 -0
  160. package/engines/specs/realtime_index.yaml +34 -0
  161. package/engines/specs/ror.yaml +20 -0
  162. package/engines/specs/satnogs.yaml +20 -0
  163. package/engines/specs/sec_edgar.yaml +46 -0
  164. package/engines/specs/skillsmp.yaml +50 -0
  165. package/engines/specs/sogou_weixin_browser.yaml +30 -0
  166. package/engines/specs/soilgrids.yaml +25 -0
  167. package/engines/specs/sspai.yaml +36 -0
  168. package/engines/specs/stackexchange.yaml +46 -0
  169. package/engines/specs/std_samr.yaml +21 -0
  170. package/engines/specs/tass.yaml +43 -0
  171. package/engines/specs/tle_mirror.yaml +21 -0
  172. package/engines/specs/train.yaml +37 -0
  173. package/engines/specs/tvmaze.yaml +20 -0
  174. package/engines/specs/twitter_syndication.yaml +31 -0
  175. package/engines/specs/un_comtrade.yaml +23 -0
  176. package/engines/specs/unpaywall.yaml +54 -0
  177. package/engines/specs/vnpress.yaml +43 -0
  178. package/engines/specs/weather.yaml +32 -0
  179. package/engines/specs/who_don.yaml +21 -0
  180. package/engines/specs/who_gho.yaml +20 -0
  181. package/engines/specs/wikimedia_commons.yaml +34 -0
  182. package/engines/specs/wikisource.yaml +22 -0
  183. package/engines/specs/worms.yaml +19 -0
  184. package/engines/specs/x_trending.yaml +34 -0
  185. package/engines/specs/yna.yaml +43 -0
  186. package/engines/specs/ynet.yaml +43 -0
  187. package/engines/specs/zbmath.yaml +40 -0
  188. package/engines/specs/zdic.yaml +22 -0
  189. package/engines/specs/zenodo.yaml +27 -0
  190. package/engines/specs/zhihu_hot_app.yaml +35 -0
  191. package/mcp/clients.yaml +74 -0
  192. package/package.json +51 -12
  193. package/packages/dsh-plugin/README.md +134 -0
  194. package/packages/dsh-plugin/cordis.patch.yml +48 -0
  195. package/packages/dsh-plugin/dsh/client.js +1244 -0
  196. package/packages/dsh-plugin/dsh/index.js +2290 -0
  197. package/packages/dsh-plugin/dsh/native-tools.mjs +743 -0
  198. package/packages/dsh-plugin/package.json +38 -0
  199. package/packages/dsh-plugin/test/client.test.js +232 -0
  200. package/packages/dsh-plugin/test/config.test.js +30 -0
  201. package/packages/dsh-plugin/test/index.test.js +1338 -0
  202. package/references/query-templates.md +96 -0
  203. package/references/query-templates.yaml +118 -0
  204. package/scripts/ab_eval.py +219 -0
  205. package/scripts/ab_eval_p0p1.py +266 -0
  206. package/scripts/adaptive.py +271 -70
  207. package/scripts/answer.py +154 -0
  208. package/scripts/archive_run.py +591 -0
  209. package/scripts/argo_engine_registry.py +172 -0
  210. package/scripts/argo_paths.py +728 -0
  211. package/scripts/article.py +136 -0
  212. package/scripts/arxiv_source.py +201 -0
  213. package/scripts/badcase_ledger.py +252 -0
  214. package/scripts/batch_probe.py +241 -0
  215. package/scripts/benchmark.py +19 -0
  216. package/scripts/bounded_run.py +144 -0
  217. package/scripts/browser_auth.py +323 -0
  218. package/scripts/burstiness_detector.py +147 -0
  219. package/scripts/cache.py +1078 -67
  220. package/scripts/cache_guard.py +271 -0
  221. package/scripts/cache_key_vdom.py +56 -0
  222. package/scripts/cache_similarity.py +170 -0
  223. package/scripts/caliber_isolation.py +195 -0
  224. package/scripts/calibrate_lowquality.py +210 -0
  225. package/scripts/candidate_envelope.py +366 -0
  226. package/scripts/chrome_cdp.py +871 -0
  227. package/scripts/circuit_breaker.py +389 -0
  228. package/scripts/citations.py +334 -0
  229. package/scripts/cite_cli.py +59 -0
  230. package/scripts/cjk_tokens.py +95 -0
  231. package/scripts/clarify.py +47 -24
  232. package/scripts/cli_io.py +240 -0
  233. package/scripts/config.py +683 -45
  234. package/scripts/config_cache.py +402 -0
  235. package/scripts/conn_pool.py +220 -0
  236. package/scripts/content_security.py +685 -0
  237. package/scripts/content_signals.py +730 -0
  238. package/scripts/crawl.py +74 -35
  239. package/scripts/daemon.py +866 -0
  240. package/scripts/digup_bridge.py +214 -0
  241. package/scripts/engine_admission.py +366 -0
  242. package/scripts/engine_dispatch.py +1019 -0
  243. package/scripts/engine_env.py +534 -0
  244. package/scripts/engine_failure.py +411 -0
  245. package/scripts/engine_families.py +732 -0
  246. package/scripts/engine_policy.py +218 -0
  247. package/scripts/engine_requires.py +190 -0
  248. package/scripts/engine_status.py +322 -0
  249. package/scripts/engine_validate.py +638 -0
  250. package/scripts/engines.py +778 -294
  251. package/scripts/engines_base.py +1521 -0
  252. package/scripts/engines_builders.py +298 -0
  253. package/scripts/engines_builders_batch10.py +159 -0
  254. package/scripts/engines_builders_batch11.py +174 -0
  255. package/scripts/engines_builders_batch12.py +103 -0
  256. package/scripts/engines_builders_batch13.py +340 -0
  257. package/scripts/engines_builders_batch9.py +1468 -0
  258. package/scripts/engines_builders_cn.py +2283 -0
  259. package/scripts/engines_builders_data.py +2923 -0
  260. package/scripts/engines_builders_data_macro.py +775 -0
  261. package/scripts/engines_builders_feeds.py +255 -0
  262. package/scripts/engines_builders_intl.py +1239 -0
  263. package/scripts/engines_builders_search.py +440 -0
  264. package/scripts/engines_builders_tech.py +1360 -0
  265. package/scripts/evidence.py +588 -162
  266. package/scripts/evidence_loop.py +592 -0
  267. package/scripts/evidence_tier.py +298 -0
  268. package/scripts/except_sets.py +25 -0
  269. package/scripts/extract.py +55 -16
  270. package/scripts/fact_align.py +207 -0
  271. package/scripts/fact_crosscheck.py +230 -0
  272. package/scripts/fetch.py +25 -12
  273. package/scripts/fetch_browser.py +87 -0
  274. package/scripts/fetch_jsrun.py +122 -0
  275. package/scripts/fetch_quality.py +225 -0
  276. package/scripts/fetch_render_tinyfish.py +117 -0
  277. package/scripts/fetch_v3.py +1779 -0
  278. package/scripts/focus_extract.py +350 -0
  279. package/scripts/fulltext_store.py +169 -0
  280. package/scripts/fxtwitter_api.py +325 -0
  281. package/scripts/gen_engine_catalog.py +364 -0
  282. package/scripts/gen_native_tools.py +91 -0
  283. package/scripts/gen_routing_snapshot.py +184 -0
  284. package/scripts/health_check.py +140 -402
  285. package/scripts/health_probe.py +23 -8
  286. package/scripts/hot_state.py +134 -0
  287. package/scripts/http_client.py +1053 -0
  288. package/scripts/image_ops.py +430 -0
  289. package/scripts/image_vision/vision_probe +0 -0
  290. package/scripts/image_vision/vision_probe.swift +126 -0
  291. package/scripts/install.ps1 +148 -0
  292. package/scripts/install.sh +206 -0
  293. package/scripts/job.py +1186 -0
  294. package/scripts/jump_resolver.py +235 -0
  295. package/scripts/lang_capability.py +150 -0
  296. package/scripts/lang_detect.py +289 -0
  297. package/scripts/lang_matrix_probe.py +329 -0
  298. package/scripts/lang_pref.py +311 -0
  299. package/scripts/link_source.py +340 -0
  300. package/scripts/local_engines.py +321 -0
  301. package/scripts/local_image.py +970 -0
  302. package/scripts/local_seek.py +366 -0
  303. package/scripts/macro_countries.py +82 -0
  304. package/scripts/matrix_search_eval.py +1105 -0
  305. package/scripts/mcp_diag.py +8 -3
  306. package/scripts/mcp_handlers.py +1074 -0
  307. package/scripts/mcp_handlers_surface.py +157 -0
  308. package/scripts/mcp_launch.sh +122 -0
  309. package/scripts/mcp_server.py +118 -417
  310. package/scripts/mcp_setup.py +407 -0
  311. package/scripts/mcp_tools.py +330 -0
  312. package/scripts/mcp_transport.py +191 -0
  313. package/scripts/min_version_scan.py +335 -0
  314. package/scripts/net_proxy.py +258 -0
  315. package/scripts/network_aware.py +152 -0
  316. package/scripts/paper.py +274 -0
  317. package/scripts/pdf_extract.py +518 -0
  318. package/scripts/phrase_filter.py +66 -0
  319. package/scripts/plan.py +422 -0
  320. package/scripts/postprocess_signals.py +150 -0
  321. package/scripts/pre-commit +48 -0
  322. package/scripts/query_enhance.py +157 -0
  323. package/scripts/query_operators.py +196 -0
  324. package/scripts/query_rewriter.py +116 -7
  325. package/scripts/query_signals.py +300 -0
  326. package/scripts/query_templates.py +167 -0
  327. package/scripts/query_understanding.py +411 -0
  328. package/scripts/query_variants.py +298 -0
  329. package/scripts/quota.py +488 -76
  330. package/scripts/rank_signals.py +775 -0
  331. package/scripts/ranking_eval.py +319 -0
  332. package/scripts/readability_extract.py +433 -0
  333. package/scripts/recompute.py +415 -0
  334. package/scripts/recovery.py +616 -0
  335. package/scripts/recovery_l0.py +160 -0
  336. package/scripts/redskill/redskill_engine.py +332 -0
  337. package/scripts/regression_p0p1.py +318 -0
  338. package/scripts/replay_eval.py +640 -0
  339. package/scripts/rerank_tfidf.py +225 -0
  340. package/scripts/research.py +591 -403
  341. package/scripts/research_cli.py +361 -0
  342. package/scripts/research_dossier.py +492 -0
  343. package/scripts/research_expand.py +146 -0
  344. package/scripts/research_gates.py +272 -0
  345. package/scripts/research_report.py +209 -0
  346. package/scripts/research_strategy.py +37 -0
  347. package/scripts/research_work_packages.py +195 -0
  348. package/scripts/result_lang.py +311 -0
  349. package/scripts/robots_guard.py +259 -0
  350. package/scripts/route.py +921 -254
  351. package/scripts/route_bangs.py +40 -0
  352. package/scripts/route_cache.py +225 -0
  353. package/scripts/route_combo.py +910 -0
  354. package/scripts/route_domains.py +328 -0
  355. package/scripts/route_lang.py +605 -0
  356. package/scripts/route_log.py +63 -0
  357. package/scripts/route_policy.py +250 -0
  358. package/scripts/rrf_classic.py +66 -0
  359. package/scripts/screenshot.py +73 -0
  360. package/scripts/search.py +897 -405
  361. package/scripts/search_attribution.py +88 -0
  362. package/scripts/search_benchmark.py +407 -0
  363. package/scripts/search_cli.py +627 -0
  364. package/scripts/search_entry.py +389 -0
  365. package/scripts/search_output.py +606 -0
  366. package/scripts/search_pipeline.py +1077 -0
  367. package/scripts/search_rank.py +991 -0
  368. package/scripts/search_types.py +27 -12
  369. package/scripts/seek_locator.py +68 -0
  370. package/scripts/semantic_evidence.py +215 -0
  371. package/scripts/serp_guard.py +228 -0
  372. package/scripts/serp_kill_log.py +51 -0
  373. package/scripts/single_flight.py +120 -0
  374. package/scripts/social_engines/__init__.py +10 -0
  375. package/scripts/social_engines/bilibili_engine.py +131 -0
  376. package/scripts/social_engines/hackernews_engine.py +113 -0
  377. package/scripts/social_engines/reddit_engine.py +172 -0
  378. package/scripts/social_engines/twitter_engine.py +397 -0
  379. package/scripts/social_engines/v2ex_engine.py +101 -0
  380. package/scripts/social_engines/weibo_engine.py +128 -0
  381. package/scripts/social_engines/xiaohongshu_engine.py +137 -0
  382. package/scripts/social_engines/zhihu_engine.py +139 -0
  383. package/scripts/social_research.py +201 -0
  384. package/scripts/sogou_weixin_browser.py +318 -0
  385. package/scripts/source_ledger.py +249 -0
  386. package/scripts/stage_timing.py +58 -0
  387. package/scripts/stats_cli.py +95 -0
  388. package/scripts/straggler_policy.py +60 -0
  389. package/scripts/stylometry_detector.py +231 -0
  390. package/scripts/sync_backends.py +353 -0
  391. package/scripts/sync_installs.py +29 -0
  392. package/scripts/template_cli.py +127 -0
  393. package/scripts/text_lexicon.py +72 -0
  394. package/scripts/tfidf_router.py +109 -37
  395. package/scripts/time_utils.py +233 -0
  396. package/scripts/topic_research_profiles.py +643 -0
  397. package/scripts/train.py +737 -0
  398. package/scripts/tweet.py +596 -0
  399. package/scripts/url_canon.py +217 -0
  400. package/scripts/url_optimize.py +56 -0
  401. package/scripts/url_safety.py +236 -0
  402. package/scripts/usage_log.py +116 -0
  403. package/scripts/usage_log_clean.py +113 -0
  404. package/scripts/v2ex_nodes.py +311 -0
  405. package/scripts/variant_recall.py +188 -0
  406. package/scripts/watch.py +205 -0
  407. package/scripts/wechat_article.py +258 -0
  408. package/scripts/wide_research.py +402 -0
  409. package/scripts/wx.py +349 -0
  410. package/scripts/x_article_fetch.py +141 -0
  411. package/scripts/x_search.py +234 -0
  412. package/scripts/x_trending.py +189 -0
  413. package/scripts/yaml_load.py +67 -0
  414. package/sub-skills/ego-search/SKILL.md +253 -0
  415. package/sub-skills/ego-search/references/browser-runtime.md +43 -0
  416. package/sub-skills/ego-search/references/install.md +67 -0
  417. package/sub-skills/ego-search/references/original-ego-upgrade.md +51 -0
  418. package/sub-skills/ego-search/scripts/ego_search.py +800 -0
  419. package/sub-skills/ego-search/scripts/merge.py +226 -0
  420. package/sub-skills/ego-search/scripts/quality.py +64 -0
  421. package/sub-skills/ego-search/scripts/runtime.py +172 -0
  422. package/sub-skills/ego-search/scripts/safety.py +109 -0
  423. package/sub-skills/ego-search/scripts/serp_spec.py +109 -0
  424. package/sub-skills/ego-search/scripts/webbridge_adapter.py +374 -0
  425. package/sub-skills/ego-search/tests/test_query_normalize.py +68 -0
  426. package/sub-skills/js-run/SKILL.md +67 -0
  427. package/sub-skills/js-run/scripts/jsrun.py +112 -0
  428. package/sub-skills/js-run/scripts/shim.js +188 -0
  429. package/sub-skills/js-run/tests/fixtures/challenge_like.js +27 -0
  430. package/sub-skills/js-run/tests/test_jsrun.py +165 -0
  431. package/sub-skills/local-search/SKILL.md +50 -53
  432. package/sub-skills/local-search/bm25.py +162 -0
  433. package/sub-skills/local-search/config.yaml +152 -55
  434. package/sub-skills/local-search/engine_registry.py +91 -26
  435. package/sub-skills/local-search/{health_check.py → local_health_check.py} +140 -10
  436. package/sub-skills/local-search/local_search_adapter.py +13 -2
  437. package/sub-skills/local-search/parse_maps.yaml +40 -42
  438. package/sub-skills/local-search/search_v3.py +1182 -65
  439. package/sub-skills/local-search/smart_router.py +47 -7
  440. package/sub-skills/local-seek/SKILL.md +110 -0
  441. package/sub-skills/local-seek/config/domains.yaml +20 -0
  442. package/sub-skills/local-seek/references/auto-behaviors.md +24 -0
  443. package/sub-skills/local-seek/references/fd-mdfind-recipes.md +62 -0
  444. package/sub-skills/local-seek/references/git-integration.md +54 -0
  445. package/sub-skills/local-seek/references/remote-handoff.md +46 -0
  446. package/sub-skills/local-seek/references/rg-recipes.md +96 -0
  447. package/sub-skills/local-seek/references/strategies.md +52 -0
  448. package/sub-skills/local-seek/references/structural-search.md +59 -0
  449. package/sub-skills/local-seek/scripts/eval_rank.py +216 -0
  450. package/sub-skills/local-seek/scripts/eval_seek.py +224 -0
  451. package/sub-skills/local-seek/scripts/seek.py +1465 -0
  452. package/sub-skills/local-seek/scripts/seek_frecency.py +126 -0
  453. package/sub-skills/local-seek/scripts/seek_fts.py +430 -0
  454. package/sub-skills/local-seek/scripts/seek_rank.py +193 -0
  455. package/sub-skills/local-seek/tests/test_content_rank.py +222 -0
  456. package/sub-skills/local-seek/tests/test_determinism_20261006.py +145 -0
  457. package/sub-skills/local-seek/tests/test_noise_tier.py +101 -0
  458. package/sub-skills/local-seek/tests/test_pcre2_probe.py +136 -0
  459. package/sub-skills/local-seek/tests/test_rank_pinyin.py +77 -0
  460. package/sub-skills/local-seek/tests/test_regression_20261003.py +169 -0
  461. package/sub-skills/local-seek/tests/test_regression_20261006.py +146 -0
  462. package/sub-skills/local-seek/tests/test_seek_degradation.py +111 -0
  463. package/sub-skills/local-seek/tests/test_seek_fts.py +313 -0
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env python3
2
+ """route_policy.py — 预算与保留策略(combo 定稿的最后一道)。
3
+
4
+ 职责只有两件:把 combo 截到本次 mode/depth/context 允许的规模;决定谁在截断
5
+ 中必须留下(must_keep、垂直域主源、新专源加槽)。本模块不做语言判断、不做族
6
+ 去重——那些是 route_combo / route_lang 的事。
7
+
8
+ 为什么单独成模块:加槽机制(批次九)与预算截断曾经与「谁该在场」混在同一个
9
+ 千行函数里,导致「路由命中但零结果」这类缺陷只能在结果侧观察到。
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Any
15
+
16
+
17
+ _VERTICAL_NEW_SOURCE: dict[str, tuple[str, ...]] = {
18
+ "species_search": ("worms",), # 海洋分类学权威命名,无重叠
19
+ "medical": ("who_don",), # 疫情通报,与 clinicaltrials/openfda 不同能力
20
+ "book_search": ("k10plus",), # 德语区最大联合目录,补区域空白
21
+ "film_search": ("tvmaze",), # 电视剧元数据(imdb/douban 偏电影)
22
+ "sports_search": ("openf1", "openligadb"), # F1/德甲结构化赛程比分
23
+ "org_entity": ("ror",), # 研究机构标识(含域名映射)
24
+ "media_search": ("deezer", "listenbrainz"), # 国际曲库 + 开源收听记录,能力互不重叠
25
+ # 2026-09-16:五个免密钥国内源接线。共同点是「补结构性空白」而非同质重复,
26
+ # 故声明在既有源之后、由本表加槽,不用新源挤掉既有源的位次。
27
+ "hot_trending": ("weibo_hot", "douyin_hot"), # 微博/抖音两条主榜单,该域原先一条都没有
28
+ "cn_tech_community": ("csdn",), # 中文技术社区最大一站,补掘金/少数派之外
29
+ "financial_news": ("wallstreetcn",), # 快讯流上游与财联社/金十不同源
30
+ "weather_query": ("weather_cn",), # 国内城市实况,补国际源的城市覆盖缺口
31
+ # 2026-09-17:国际新闻与事实核查两个新域。前者的三个种子按 feed_mode=hot
32
+ # 给「最新流」语义(与话题检索分流,见 engines_builders_feeds 说明);
33
+ # 后者补声明级核验——argo 此前没有任何「这个说法被判真伪」的一手源。
34
+ "intl_news_flash": ("guardian_rss", "france24", "dw_news"), # 一手外媒实时流,补英文主流媒体直采空白
35
+ "claim_check": ("factcheck_org", "full_fact"), # 美/英两法域核查口径
36
+ # 2026-09-19:academic 域两个源。core 是**新增**(开放获取全文 + PDF 直链,
37
+ # 与 openalex/crossref 的元数据、arxiv/biorxiv 的预印本分层不同);
38
+ # local_pubmed 是**修复**(旧实现静默 400 且解析不出字符串数组,实测 0 条,
39
+ # 详见 engines_builders_batch9._build_pubmed_engine 文档串)。两者声明在
40
+ # 既有源之后,由本表加槽,不挤掉 arxiv/openreview 等既有位次。
41
+ "academic": ("local_pubmed", "core", "cinii"), # 生物医学全文 + 机构仓储开放获取 + 日本学术 + 数学索引
42
+ # 2026-09-21:academic 补两个国别/学科专门源。位次 5/6 是照本域上方注释
43
+ # 的既有实践选的(deepest=6 → 加槽后预算覆盖到 6,前四位次一律不动)。
44
+ # cinii 声明 langs=ja,靠 engines_demote_for_lang 的语言专用源降级,
45
+ # 只在日语查询里占位;zbmath 语言中立,数学查询与 deep 档可达。
46
+ "soil_agri": ("openfoodfacts",), # 食品成分库:补 usda(单一国别)之外的多国食品数据
47
+ }
48
+
49
+
50
+ _VERTICAL_KEEP: frozenset[str] = frozenset({
51
+ "film_search", "sports_search", "geo_places", "org_entity", "media_search",
52
+ "modal_card",
53
+ "astro_space", "energy_grid", "transport_rt", "vehicle_data",
54
+ "japan_law", "soil_agri", "species_search", "art_museum",
55
+ "anime_encyclopedia", "book_search", "medical", "earth_science",
56
+ })
57
+
58
+
59
+ def _new_source_budget_extra(
60
+ domain: dict[str, Any] | None,
61
+ engines_combo: list[str],
62
+ enabled: set[str],
63
+ *,
64
+ mode: str,
65
+ depth: str,
66
+ context: str,
67
+ live_combo: list[str] | None = None,
68
+ ) -> int:
69
+ """垂直域「新专源」的加槽额度(0 = 不加槽,行为与改造前逐位一致)。
70
+
71
+ 按新专源在 combo 中的**最深位次**定额度,保证它落在本模式预算之内:
72
+ 位次 d 的源需要 budget >= d,故 extra = max(d - base, 0)。
73
+
74
+ 调用方应传域**声明**的 combo(不是已被前置裁剪动过的当前列表),
75
+ 否则新源被摘掉后额度恒为 0——详见
76
+ `_apply_policy_with_new_source_slots` 的说明。
77
+
78
+ `live_combo` 是当前(已被上游重排过的)combo,用于第二处位次:新源**还在
79
+ combo 里、但被重排推到预算窗口之外**。只按声明位次定额度会漏掉这一态——
80
+ 声明位次恰好等于预算时(financial_news 的 wallstreetcn:位次 3 = 预算 3)
81
+ extra 恒为 0,而 `_apply_policy_with_new_source_slots` 的 must_keep 补位
82
+ 只在「源已不在 combo 里」时触发,两处保护同时失效,源被静默截断。
83
+ 2026-09-16 实测:「财经」丢掉 wallstreetcn、「财经新闻」保住,同一个域
84
+ 两种结果。位次取当前 combo 的较大者后额度随之抬高,新源留在预算内,且
85
+ 额度是**扩容**不是腾位——既有源一个不少。
86
+
87
+ 上限按模式分档 —— fast 强制串行(见 `_apply_intent_parallelism`),加槽直接
88
+ 乘在延迟上,故上限 2;auto/balanced 走并行,放宽到 4。deep/research 本就
89
+ 不截断(base 为 None),extra 无意义。
90
+
91
+ domain 可能为 None(TF-IDF 无命中时的 catch-all 分支),此时无域可谈,返回 0。
92
+ """
93
+ if not domain or not engines_combo:
94
+ return 0
95
+
96
+ # 学术域固定加成:该域有 11+ 个引擎(arxiv/openreview/biorxiv/openalex/
97
+ # crossref/europepmc/dblp/semantic_scholar/local_pubmed/core/cinii),
98
+ # auto 模式 budget=3 只够前 3 个,后 8 个永远轮不到。学术搜索需要多源
99
+ # 交叉验证才严谨,固定 +3 让 budget 达到 6,覆盖到 semantic_scholar。
100
+ if domain.get("name") == "academic":
101
+ try:
102
+ from engine_policy import combo_budget
103
+ base = combo_budget(mode=mode, depth=depth, context=context)
104
+ if base is not None:
105
+ return min(3, max(0, 6 - base))
106
+ except Exception:
107
+ pass
108
+
109
+ pending = [
110
+ e for e in _VERTICAL_NEW_SOURCE.get(domain.get("name"), ())
111
+ if e in engines_combo and e in enabled
112
+ ]
113
+ if not pending:
114
+ return 0
115
+ deepest = max(engines_combo.index(e) + 1 for e in pending)
116
+ if live_combo:
117
+ # 新源在 live_combo 里的位次(可能比声明位次更靠后,见 docstring)
118
+ deepest = max(
119
+ [deepest] + [live_combo.index(e) + 1 for e in pending if e in live_combo]
120
+ )
121
+ try:
122
+ from engine_policy import combo_budget
123
+ base = combo_budget(mode=mode, depth=depth, context=context)
124
+ except Exception:
125
+ return 0
126
+ if base is None: # 不截断的模式(deep/research)
127
+ return 0
128
+ cap = 2 if ((mode or "auto") in ("fast", "budget")
129
+ or (depth or "fast") == "fast") else 4
130
+ return min(max(deepest - base, 0), cap)
131
+
132
+
133
+ def _apply_engine_policy(
134
+ engines_combo: list[str],
135
+ *,
136
+ mode: str = "auto",
137
+ depth: str = "fast",
138
+ context: str = "search",
139
+ engines_boost: list[str] | None = None,
140
+ enabled: set[str] | None = None,
141
+ must_keep: list[str] | None = None,
142
+ budget_extra: int = 0,
143
+ ) -> list[str]:
144
+ """boost 垂直源 + tier/budget 截断(单一策略入口)。
145
+
146
+ must_keep:预算截断后仍强制保留的引擎(如 geo 的 local_openstreetmap),
147
+ 必要时从尾部腾位,避免特化源被 budget 裁掉。
148
+
149
+ budget_extra:垂直域新专源的**加槽**额度。与 must_keep 的区别是「不腾位、
150
+ 只扩容」——must_keep 会挤掉既有可用源(实测会把 douban_movie/musicbrainz
151
+ 挤出),而新专源与既有源多为互补能力,应当共存而非替换。
152
+ """
153
+ try:
154
+ from engine_policy import boost_into_combo, combo_budget, filter_combo_by_policy
155
+ except ImportError:
156
+ return engines_combo
157
+ out = list(engines_combo or [])
158
+ if engines_boost:
159
+ out = boost_into_combo(out, engines_boost, enabled=enabled)
160
+ out = filter_combo_by_policy(out, mode=mode, depth=depth, context=context,
161
+ budget_extra=budget_extra)
162
+ if must_keep:
163
+ budget = combo_budget(mode=mode, depth=depth, context=context,
164
+ extra=budget_extra)
165
+ keep_set = set(must_keep)
166
+ for e in must_keep:
167
+ if not e or e in out:
168
+ continue
169
+ # must_keep 强制保留,不因 enabled 缺失丢弃
170
+ # (modal_card 缺 key 时仍保留 bocha_ai/bocha,由执行层返回 error item)
171
+ if budget is not None and len(out) >= budget:
172
+ # 替换末位「非保底」成员,腾出槽位;保底成员之间不互踩
173
+ # (modal_card 整 combo 保底:bocha/train 依次补位时不得顶掉彼此)
174
+ replace_idx = next(
175
+ (i for i in range(len(out) - 1, -1, -1)
176
+ if out[i] not in keep_set),
177
+ None,
178
+ )
179
+ if replace_idx is not None:
180
+ out = out[:replace_idx] + out[replace_idx + 1:] + [e]
181
+ else:
182
+ # 尾部全是保底成员:直接追加(保底优先于预算)
183
+ out.append(e)
184
+ else:
185
+ out.append(e)
186
+ # 去重保序
187
+ seen: set[str] = set()
188
+ deduped: list[str] = []
189
+ for e in out:
190
+ if e not in seen:
191
+ seen.add(e)
192
+ deduped.append(e)
193
+ out = deduped
194
+ return out
195
+
196
+
197
+ def _apply_policy_with_new_source_slots(
198
+ domain: dict[str, Any] | None,
199
+ engines_combo: list[str],
200
+ *,
201
+ mode: str,
202
+ depth: str,
203
+ context: str,
204
+ enabled: set[str] | None = None,
205
+ engines_boost: list[str] | None = None,
206
+ must_keep: list[str] | None = None,
207
+ ) -> list[str]:
208
+ """按域预算截断 combo,并为该域的「新专源」加槽(不腾位)。
209
+
210
+ 正则域命中分支与 catch-all 分支此前各抄一份
211
+ `_new_source_budget_extra(...)` + `_apply_engine_policy(...)`(参数与注释
212
+ 逐字相同);收紧成单一入口后,加槽计算方式只有一处可改。
213
+
214
+ **为什么额度按「声明位次」而非当前 combo 算**:进到这里的 combo 已经被
215
+ 两道前置裁剪动过手——`_get_engines_combo` 的 web_general 能力族去重
216
+ (max_per_family=2)与 `_apply_intent_parallelism` 的意图裁剪。新专源
217
+ 声明在 combo 后排,正是这两道裁剪的常客,源一旦被摘掉,按当前 combo
218
+ 算的额度就恒为 0,加槽机制被静默废掉。实测两例(2026-09-13):
219
+ - sports_search:openf1/openligadb 未声明 family → 落 web_general,
220
+ 被族去重摘掉,加槽恒不生效;
221
+ - org_entity:ror 被意图裁剪摘掉,加槽恒不生效。
222
+ 故额度按域**声明**的位次算;被摘掉的新专源在同一额度内补回(额度不够
223
+ 时不强塞,交回既有 must_keep 换位逻辑,避免反过来挤掉既有源)。
224
+
225
+ 额度取「声明位次」与「当前 combo 位次」的**较大者**(`live_combo` 参数)。
226
+ 只取声明位次还有第二种失效态:源**没被摘掉,只是被排到窗口之外**。此时
227
+ `e not in engines_combo` 为假,上面那段补位不触发;而声明位次恰好等于预算
228
+ 时 extra 也是 0——两处保护同时失效,源被预算静默截断。实测(2026-09-16)
229
+ financial_news 的 wallstreetcn:声明位次 3 = auto/balanced 预算 3,查询
230
+ 「财经」时被自适应重排挤到 eastmoney 之后而落选,「财经新闻」时保住。
231
+ 取较大者后该源额度为 1,两个源并存(扩容而非腾位)。
232
+ """
233
+ declared = list((domain or {}).get("engines_combo") or [])
234
+ live = [e for e in _VERTICAL_NEW_SOURCE.get((domain or {}).get("name"), ())
235
+ if e in declared and (enabled is None or e in enabled)]
236
+ keep = list(must_keep or [])
237
+ for e in live:
238
+ if e not in engines_combo and e not in keep:
239
+ keep.append(e)
240
+ return _apply_engine_policy(
241
+ engines_combo, mode=mode, depth=depth, context=context,
242
+ engines_boost=engines_boost, enabled=enabled,
243
+ must_keep=keep or None,
244
+ budget_extra=_new_source_budget_extra(
245
+ domain, declared or engines_combo, enabled or set(),
246
+ mode=mode, depth=depth, context=context,
247
+ # 传当前 combo:新源还在里面但被重排推出窗口时,额度要按它在
248
+ # 当前 combo 的位次算(只在声明位次上算会得到 0,见该函数说明)
249
+ live_combo=engines_combo),
250
+ )
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """rrf_classic.py — 经典 RRF 融合(weighted=False 路径)。
3
+
4
+ 所有引擎列表在同一个池中竞争,每个列表独立贡献排名。
5
+ 为什么单独成模块:search_rank.py 已压着祖父上限,经典 RRF 路径
6
+ 作为独立模块拆出后,search_rank.py 只留调用点。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+
13
+
14
+ def rrf_classic(
15
+ ranked_lists: list[list[dict[str, Any]]],
16
+ k: int = 60,
17
+ lang: str | None = None,
18
+ _canonical_url=None,
19
+ ) -> list[dict[str, Any]]:
20
+ """经典 RRF:所有结果在同一个池中竞争,不分组。
21
+
22
+ _canonical_url 由调用方(search_rank)传入,避免本模块反向依赖。
23
+ """
24
+ if _canonical_url is None:
25
+ from url_canon import canonical_url as _canonical_url
26
+
27
+ scores: dict[str, float] = {}
28
+ items: dict[str, dict[str, Any]] = {}
29
+ for _li, results in enumerate(ranked_lists):
30
+ for i, r in enumerate(results):
31
+ key = (
32
+ _canonical_url(r.get("url", ""))
33
+ or (f"__title__:{r.get('title', '')}" if r.get("title") else "")
34
+ or (f"__card__:{r.get('card_type', '')}" if r.get("card_type") else "")
35
+ or f"__idx__:{_li}:{i}"
36
+ )
37
+ scores[key] = scores.get(key, 0.0) + 1.0 / (k + i + 1)
38
+ eng = r.get("_engine") or r.get("source", "") or ""
39
+ if key not in items:
40
+ item = dict(r)
41
+ item["_rrf_score"] = 0.0
42
+ cons: list[str] = []
43
+ if eng:
44
+ cons.append(eng)
45
+ item["consensus_engines"] = cons
46
+ items[key] = item
47
+ else:
48
+ cur = items[key]
49
+ new_txt = f"{r.get('title', '')} {r.get('snippet', '')}"
50
+ cur_txt = f"{cur.get('title', '')} {cur.get('snippet', '')}"
51
+ if len(new_txt) > len(cur_txt):
52
+ cur["title"] = r.get("title", cur.get("title"))
53
+ cur["snippet"] = r.get("snippet", cur.get("snippet"))
54
+ sources = {cur.get("source", ""), r.get("source", "")}
55
+ cur["source"] = "/".join(s for s in sources if s)
56
+ cons = list(cur.get("consensus_engines") or [])
57
+ if eng and eng not in cons:
58
+ cons.append(eng)
59
+ cur["consensus_engines"] = cons
60
+ ranked = sorted(scores.items(), key=lambda x: -x[1])
61
+ out = []
62
+ for key, _ in ranked:
63
+ item = items[key]
64
+ item["_rrf_score"] = round(scores[key], 6)
65
+ out.append(item)
66
+ return out
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env python3
2
+ """argo screenshot — 网页截图(CLI 入口)。
3
+
4
+ CLI 与 MCP 工具面保持一一对应(见 bin/argo 的 scripts 注册表注释):
5
+ MCP 有 argo_screenshot 就应有 `argo screenshot`,否则该能力只能靠默认关闭的
6
+ MCP 够得着。本文件与 mcp_handlers.py 的 argo_screenshot 分支共用 chrome_cdp。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import os
13
+ import sys
14
+ import tempfile
15
+ import time
16
+ from typing import Any
17
+ from cli_io import dumps
18
+
19
+ _SCRIPTS = os.path.dirname(os.path.realpath(__file__))
20
+ if _SCRIPTS not in sys.path:
21
+ sys.path.insert(0, _SCRIPTS)
22
+
23
+
24
+ def capture_screenshot(url: str, output: str | None = None, full_page: bool = False,
25
+ wait_until: str = "networkidle") -> dict[str, Any]:
26
+ """截图并返回与 MCP argo_screenshot 同构的结果字典。"""
27
+ import chrome_cdp
28
+
29
+ target = output or os.path.join(
30
+ tempfile.gettempdir(), f"argo_screenshot_{int(time.time())}.png")
31
+ try:
32
+ # with 上下文:无论 navigate/screenshot 成功或抛异常,
33
+ # __exit__ 都会 stop() 回收 Chrome 进程与临时目录
34
+ with chrome_cdp.ChromeCDP(auto_start=True) as cdp:
35
+ cdp.navigate(url, wait_until=wait_until)
36
+ saved = cdp.screenshot(target, full_page=full_page)
37
+ except Exception as e:
38
+ return {"success": False, "url": url, "error": str(e)[:200]}
39
+
40
+ if saved and os.path.exists(saved):
41
+ return {"success": True, "url": url, "screenshot": saved}
42
+ return {"success": False, "url": url, "error": "screenshot failed"}
43
+
44
+
45
+ def main() -> None:
46
+ p = argparse.ArgumentParser(description="Argo screenshot — 网页截图(CDP)")
47
+ p.add_argument("url", help="目标 URL")
48
+ p.add_argument("--output", "-o", default=None, help="输出 PNG 路径(默认落临时目录)")
49
+ p.add_argument("--full-page", action="store_true", help="整页截图(默认仅当前视口)")
50
+ # 只暴露 navigate 真正实现的两种策略:给 domcontentloaded 等未实现的值
51
+ # 会走 else 分支静默不等待,截到半渲染页面
52
+ p.add_argument("--wait-until", default="networkidle",
53
+ choices=["networkidle", "load"],
54
+ help="导航等待策略(默认 networkidle)")
55
+ p.add_argument("--json", action="store_true", help="JSON 输出")
56
+ args = p.parse_args()
57
+
58
+ result = capture_screenshot(args.url, output=args.output,
59
+ full_page=args.full_page,
60
+ wait_until=args.wait_until)
61
+
62
+ if args.json:
63
+ print(dumps(result))
64
+ elif result.get("success"):
65
+ print(result["screenshot"])
66
+ else:
67
+ print(f"截图失败:{result.get('error')}", file=sys.stderr)
68
+
69
+ sys.exit(0 if result.get("success") else 1)
70
+
71
+
72
+ if __name__ == "__main__":
73
+ main()