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,411 @@
1
+ #!/usr/bin/env python3
2
+ """engine_failure.py — 引擎失败归因(依赖缺失 / 认证失效 / 上游改版 / 网络)。
3
+
4
+ 背景(v2.4.2):熔断器此前只回答「要不要继续用」(open/closed/disabled),
5
+ 不回答「为什么坏」。用户看到 `--list-engines --detail` 里某引擎 blocked 或
6
+ 连续失败,只能自己猜是没登录、没装工具、还是站点改版。
7
+
8
+ 本模块把最后一次失败归类为七类,并给出对应动作:
9
+
10
+ dependency 后端命令/工具不存在或不可执行(如 xhs / tw / rdt 未安装)
11
+ → 动作:按 requires.fix 安装
12
+ quota_exhausted 余额/套餐/免费额度已耗尽(402/403 + 「余额不足」「insufficient
13
+ balance」)——充值或到下一计费周期前重试都不会成功
14
+ → 动作:充值或等周期边界自愈;期间路由自动跳过该引擎
15
+ 与 rate_limited 的区别:后者是「慢点来」,冷却几十秒后值得再试;
16
+ 前者重试只烧时间,必须驱动停用而不是短冷却。
17
+ auth 认证/授权失效(401/403、login required、cookie 过期)
18
+ → 动作:重新登录(如 `xhs login`),并注意结果应进登录态分区
19
+ rate_limited 限流(429/Retry-After)——源端在说「慢点来」,引擎本身是好的
20
+ → 动作:等待后重试;不触发降权,不应累计进引擎故障
21
+ blocked 拿到内容之前被拦截(反爬页面 / TLS 指纹识别 / WAF 挑战页)。
22
+ 与 auth 的区分:auth 是「内容存在但你没资格」,blocked 是
23
+ 「请求在到达内容前就被机器判定挡下」——重登录无用,
24
+ 换客户端形态(请求头完整度 / TLS 指纹 / 浏览器通道)才有救
25
+ → 动作:升级请求形态或切换浏览器态通道;不该当作引擎故障降权
26
+ upstream 上游改版(404 找不到接口、5xx 持续、HTML 结构不再匹配)
27
+ → 动作:引擎实现需跟进(解析器/接口路径过期)
28
+ network 网络层问题(超时、DNS、连接重置、SSL)
29
+ → 动作:重试或换网络;通常不需改代码
30
+
31
+ 设计原则:
32
+ - 分类是**纯函数**:输入 (异常/状态码/输出文本/依赖状态),输出分类 + 依据。
33
+ 不产生副作用,便于单测与回溯。
34
+ - 只做「归类 + 给动作」,不自动改变熔断状态:熔断策略仍由 circuit_breaker
35
+ 掌管,避免两套逻辑互相打架。
36
+ - 归因置信度不足时返回 unknown 而不是硬猜——错的归因比没有归因更坏。
37
+ - 判定顺序即裁决:更具体的信号先于更泛的信号。带 auth 语义的 403
38
+ (members-only / login required)不得被误判成 blocked,反之纯 403
39
+ 叠加反爬页面特征时必须判 blocked——把「需要登录」和「被封锁」混为一谈
40
+ 会把用户支去错误的修复方向,比不给建议更糟。
41
+ """
42
+
43
+ from __future__ import annotations
44
+
45
+ import re
46
+ from typing import Any
47
+
48
+ # 分类常量
49
+ DEPENDENCY = "dependency"
50
+ AUTH = "auth"
51
+ RATE_LIMITED = "rate_limited"
52
+ QUOTA_EXHAUSTED = "quota_exhausted"
53
+ BLOCKED = "blocked"
54
+ UPSTREAM = "upstream"
55
+ NETWORK = "network"
56
+ UNKNOWN = "unknown"
57
+
58
+ # 各类对应的建议动作
59
+ _ACTIONS = {
60
+ DEPENDENCY: "按 requires.fix 安装缺失的后端命令,确保其在 PATH 上",
61
+ AUTH: "重新登录/刷新凭证;登录态结果应标记 cache_eligible=false 进独立分区",
62
+ RATE_LIMITED: "源端限流,等待后重试(尊重 Retry-After);不降权、不改代码",
63
+ QUOTA_EXHAUSTED: "配额/余额已耗尽:充值或等下一计费周期自动恢复;"
64
+ "期间自动跳过该引擎(quota.py reset 可提前恢复)",
65
+ BLOCKED: "请求在到达内容前被拦截(反爬/TLS 指纹)。升级请求形态"
66
+ "(完整浏览器请求头 / TLS 指纹 / 浏览器态通道),重登录与重试均无效",
67
+ UPSTREAM: "上游接口或页面结构可能已改版,需更新该引擎的解析实现",
68
+ NETWORK: "属网络层瞬时问题,优先重试或切换网络,通常无需改代码",
69
+ UNKNOWN: "信息不足,建议手动复现一次以定位(不要据此改代码)",
70
+ }
71
+
72
+ # 认证类信号
73
+ _AUTH_PATTERNS = (
74
+ r"\b401\b", r"unauthor", r"forbidden", r"login required",
75
+ r"not logged in", r"please log ?in", r"cookie.*(expired|invalid)",
76
+ r"token.*(expired|invalid|revoked)", r"需要登录", r"登录已过期",
77
+ r"请先登录", r"认证失败", r"无权限", r"permission denied.*auth",
78
+ )
79
+
80
+ # 封锁类信号:请求在到达内容前被机器判定挡下(反爬挑战页 / TLS 指纹识别)。
81
+ # 特征取自真实拦截页面的自述文案与握手失败字样;与 auth 信号几乎不重叠,
82
+ # 重叠处(403)由判定顺序仲裁:先 auth 语义、后封锁。
83
+ _BLOCKED_PATTERNS = (
84
+ r"just a moment", r"enable javascript and cookies", r"checking your browser",
85
+ r"cf-browser-verification", r"cf_chl", r"challenge-platform",
86
+ r"ddos-guard", r"perimeterx", r"px-captcha", r"captcha-delivery",
87
+ r"unable to handshake", r"handshake failure", r"sslv3_alert",
88
+ r"access denied", r"request blocked", r"banned", r"防火墙", r"访问被拒",
89
+ r"验证码", r"安全验证", r"滑动验证",
90
+ )
91
+
92
+ # 限流类信号(含「额度/套餐」——源端说「现在不能用」,动作同为止损等待/升配额,
93
+ # 不是改代码、也不是重新登录)
94
+ _RATE_LIMITED_PATTERNS = (
95
+ r"\b429\b", r"too many requests", r"rate limit", r"ratelimit",
96
+ r"quota.*(exceed|exhausted| depleted)", r"请求过于频繁", r"限流", r"访问频率",
97
+ r"not enough money", r"package quota", r"insufficient (funds|balance|credit|quota)",
98
+ r"(余额|额度|配额).{0,4}(不足|不够|耗尽)", r"(套餐|package).{0,12}(到期|用尽|不足|quota)",
99
+ )
100
+
101
+ # 硬配额耗尽信号(余额/套餐/免费额度)。与限流分开判定:这类失败重试不会
102
+ # 成功,必须让配额状态机停用到下一周期,而不是冷却几十秒后再撞一次。
103
+ # 只收「账户/套餐层面已没有额度」的表述;泛化的 quota exceeded 仍按限流处理
104
+ # (它常与 429 同现,且可能几小时后恢复)。
105
+ _QUOTA_EXHAUSTED_PATTERNS = (
106
+ r"insufficient (funds|balance|credit|quota)",
107
+ r"not enough (money|credit|balance)",
108
+ r"(do not|don't|does not) have enough (money|credit|balance)",
109
+ r"package quota",
110
+ r"out of credits",
111
+ r"no (remaining|available) quota",
112
+ r"quota.{0,20}(exhausted|depleted|used up)",
113
+ r"(余额|额度|配额).{0,4}(不足|不够|耗尽)",
114
+ r"(套餐|package).{0,12}(到期|用尽|不足)",
115
+ )
116
+
117
+ # 上游改版类信号
118
+ _UPSTREAM_PATTERNS = (
119
+ r"\b404\b", r"\b410\b", r"\b50[0-9]\b", r"not found", r"object not found",
120
+ r"no such (endpoint|api|route)", r"deprecated", r"api.*(changed|removed)",
121
+ r"unexpected (html|response|structure)", r"parse (error|failed)",
122
+ r"schema.*(mismatch|changed)", r"接口.*(变更|不可用|不存在)", r"页面结构",
123
+ )
124
+
125
+ # 网络类信号
126
+ _NETWORK_PATTERNS = (
127
+ r"timed? ?out", r"timeout", r"connection (reset|refused|aborted|error)",
128
+ r"name or service not known", r"temporary failure in name resolution",
129
+ r"ssl", r"tls", r"\bdns\b", r"network is unreachable", r"connectionpool",
130
+ r"超时", r"连接.*(失败|重置|被拒)", r"网络",
131
+ )
132
+
133
+ # 依赖类信号(异常类型 + 文本)
134
+ _DEPENDENCY_TYPE_NAMES = ("FileNotFoundError", "PermissionError",
135
+ "NotADirectoryError", "ImportError",
136
+ "ModuleNotFoundError")
137
+ _DEPENDENCY_PATTERNS = (
138
+ r"no such file or directory", r"command not found", r"not found in \$?PATH",
139
+ r"executable file not found", r"is not recognized as an internal",
140
+ r"找不到.*(命令|文件)", r"未安装",
141
+ )
142
+
143
+
144
+ def _matches(patterns: tuple[str, ...], text: str) -> str | None:
145
+ for p in patterns:
146
+ if re.search(p, text, re.IGNORECASE):
147
+ return p
148
+ return None
149
+
150
+
151
+ def _looks_blocked(text: str) -> bool:
152
+ """文本里是否出现封锁页特征(供状态码分支复核用)。"""
153
+ return _matches(_BLOCKED_PATTERNS, text) is not None
154
+
155
+
156
+ def classify(*,
157
+ error: BaseException | None = None,
158
+ status_code: int | None = None,
159
+ output: str | None = None,
160
+ missing_deps: list[dict[str, Any]] | None = None,
161
+ missing_env: list[str] | None = None,
162
+ anti_bot: bool | None = None) -> dict[str, Any]:
163
+ """把一次失败归类。
164
+
165
+ 判定顺序(强信号优先,避免误判):
166
+ 1. 已声明的依赖缺失(missing_deps)→ dependency(最可信,声明即证据)
167
+ 2. 已声明的密钥缺失(missing_env)→ auth
168
+ 3. 反爬页面检测显式命中(anti_bot=True)→ blocked
169
+ (调用方在拿到 HTML 时已做页面级检测,这是强证据,先于状态码——
170
+ 拦截页也常披着 200/403 的皮)
171
+ 4. 异常类型(FileNotFoundError 等)→ dependency
172
+ 5. HTTP 状态码(429 → rate_limited;402/403 带额度不足文案 → quota_exhausted;
173
+ 403 带封锁特征 → blocked,纯 403 → auth;404/410/5xx → upstream)
174
+ 6. 文本模式匹配(依次 auth → blocked → quota_exhausted → rate_limited →
175
+ dependency → upstream → network)
176
+ 7. 保底 unknown
177
+
178
+ 返回 {category, reason, evidence, action, confidence}
179
+ """
180
+ missing_deps = missing_deps or []
181
+ missing_env = missing_env or []
182
+ blob_probe = " ".join(p for p in (str(error) if error is not None else "",
183
+ output or "") if p)
184
+
185
+ # 1. 依赖声明先行:这是环境已知事实,比任何运行时猜测都可靠
186
+ if missing_deps:
187
+ bins = ", ".join(d.get("bin", "?") for d in missing_deps)
188
+ return {
189
+ "category": DEPENDENCY,
190
+ "reason": "declared-missing-deps",
191
+ "evidence": f"requires 声明缺失: {bins}",
192
+ "action": _ACTIONS[DEPENDENCY],
193
+ "confidence": "high",
194
+ }
195
+
196
+ # 2. 密钥缺失 → 认证类
197
+ if missing_env:
198
+ return {
199
+ "category": AUTH,
200
+ "reason": "declared-missing-env",
201
+ "evidence": f"缺少环境变量: {', '.join(missing_env)}",
202
+ "action": _ACTIONS[AUTH],
203
+ "confidence": "high",
204
+ }
205
+
206
+ # 3. 反爬页面显式命中:调用方做过页面级检测,强于状态码推断
207
+ if anti_bot:
208
+ return {
209
+ "category": BLOCKED,
210
+ "reason": "anti-bot-page",
211
+ "evidence": blob_probe[:200] or "拦截页特征命中",
212
+ "action": _ACTIONS[BLOCKED],
213
+ "confidence": "high",
214
+ }
215
+
216
+ # 4. 异常类型
217
+ if error is not None:
218
+ tname = type(error).__name__
219
+ if tname in _DEPENDENCY_TYPE_NAMES:
220
+ return {
221
+ "category": DEPENDENCY,
222
+ "reason": f"exception:{tname}",
223
+ "evidence": str(error)[:200],
224
+ "action": _ACTIONS[DEPENDENCY],
225
+ "confidence": "high",
226
+ }
227
+
228
+ # 5. HTTP 状态码
229
+ if status_code is not None:
230
+ # 0 = 连接层就没成(DNS 失败/拒绝/重置),没有 HTTP 响应可解释
231
+ if status_code == 0:
232
+ return {
233
+ "category": NETWORK,
234
+ "reason": "connection-failed",
235
+ "evidence": "未收到 HTTP 响应",
236
+ "action": _ACTIONS[NETWORK],
237
+ "confidence": "high",
238
+ }
239
+ # 429 与 503 同族:源站「现在不受理,稍后再说」。503 在 HTTP 层已按
240
+ # 合规等待信号处理(带 Retry-After 则等待,见 http_client 的 stop-signal
241
+ # 契约与 test_stop_signal.py);归因层若判 upstream,会把人支去「改解析
242
+ # 代码」,方向错误。故二者合并,动作同为止损等待。
243
+ if status_code in (429, 503):
244
+ return {
245
+ "category": RATE_LIMITED,
246
+ "reason": f"http-{status_code}",
247
+ "evidence": f"HTTP {status_code}",
248
+ "action": _ACTIONS[RATE_LIMITED],
249
+ "confidence": "high",
250
+ }
251
+ if status_code == 408:
252
+ return {
253
+ "category": NETWORK,
254
+ "reason": "http-408",
255
+ "evidence": "HTTP 408 请求超时",
256
+ "action": _ACTIONS[NETWORK],
257
+ "confidence": "high",
258
+ }
259
+ # 额度/套餐文案优先于鉴权仲裁:403 里写着「套餐额度不足」时,
260
+ # 让人「重新登录」是错误方向(登录改不了套餐)。search.py 的
261
+ # _QUOTA_ERROR_KEYWORDS 早就把 quota 排在 auth 之前,这里保持一致。
262
+ #
263
+ # 硬配额耗尽与限流再分一层(2026-10-18):octen 的
264
+ # `403 Insufficient balance in account` 此前落进 rate_limited,
265
+ # 只换来 60s 冷却、永不自动停用,后备链第二顺位长期是个死引擎。
266
+ # 这不是「慢点来」,重试不会成功——必须交给配额状态机停用。
267
+ if status_code in (401, 402, 403) and blob_probe:
268
+ if _matches(_QUOTA_EXHAUSTED_PATTERNS, blob_probe):
269
+ return {
270
+ "category": QUOTA_EXHAUSTED,
271
+ "reason": f"http-{status_code}+quota-exhausted",
272
+ "evidence": blob_probe[:200],
273
+ "action": _ACTIONS[QUOTA_EXHAUSTED],
274
+ "confidence": "high",
275
+ }
276
+ hit = _matches(_RATE_LIMITED_PATTERNS, blob_probe)
277
+ if hit:
278
+ return {
279
+ "category": RATE_LIMITED,
280
+ "reason": f"http-{status_code}+quota-sign",
281
+ "evidence": blob_probe[:200],
282
+ "action": _ACTIONS[RATE_LIMITED],
283
+ "confidence": "high",
284
+ }
285
+ if status_code == 401:
286
+ return {
287
+ "category": AUTH,
288
+ "reason": "http-401",
289
+ "evidence": "HTTP 401",
290
+ "action": _ACTIONS[AUTH],
291
+ "confidence": "high",
292
+ }
293
+ if status_code == 403:
294
+ # 403 有歧义:带封锁特征 → 被拦截;纯 403 → 权限/认证。
295
+ # 顺序错了会把「需要登录」的人支去装反爬对抗,反之亦然。
296
+ if _looks_blocked(blob_probe):
297
+ return {
298
+ "category": BLOCKED,
299
+ "reason": "http-403+block-sign",
300
+ "evidence": blob_probe[:200],
301
+ "action": _ACTIONS[BLOCKED],
302
+ "confidence": "high",
303
+ }
304
+ return {
305
+ "category": AUTH,
306
+ "reason": "http-403",
307
+ "evidence": "HTTP 403",
308
+ "action": _ACTIONS[AUTH],
309
+ "confidence": "high",
310
+ }
311
+ if status_code in (404, 410) or 500 <= status_code < 600:
312
+ return {
313
+ "category": UPSTREAM,
314
+ "reason": f"http-{status_code}",
315
+ "evidence": f"HTTP {status_code}",
316
+ "action": _ACTIONS[UPSTREAM],
317
+ "confidence": "high",
318
+ }
319
+ # 其余 4xx(400/402/405/406/409/413…)请求被源站拒绝,但理由无法从
320
+ # 状态码还原(参数不符?欠费?方法不对?)。按本模块纪律不硬猜:
321
+ # 继续走第 6 步找文本证据,找不到就是 unknown。
322
+
323
+ # 6. 文本模式:auth 最具体先判,封锁次之(封锁特征与 auth 语义几乎不重叠),
324
+ # 限流再后,依赖、上游、网络殿后
325
+ if blob_probe:
326
+ for patterns, category in (
327
+ (_AUTH_PATTERNS, AUTH),
328
+ (_BLOCKED_PATTERNS, BLOCKED),
329
+ # 配额耗尽先于限流:文本里同时出现「quota exhausted」与
330
+ # 「rate limit」时,前者是更具体、更可行动的结论
331
+ (_QUOTA_EXHAUSTED_PATTERNS, QUOTA_EXHAUSTED),
332
+ (_RATE_LIMITED_PATTERNS, RATE_LIMITED),
333
+ (_DEPENDENCY_PATTERNS, DEPENDENCY),
334
+ (_UPSTREAM_PATTERNS, UPSTREAM),
335
+ (_NETWORK_PATTERNS, NETWORK),
336
+ ):
337
+ hit = _matches(patterns, blob_probe)
338
+ if hit:
339
+ return {
340
+ "category": category, "reason": f"text:{hit}",
341
+ "evidence": blob_probe[:200], "action": _ACTIONS[category],
342
+ "confidence": "medium",
343
+ }
344
+
345
+ return {
346
+ "category": UNKNOWN,
347
+ "reason": "insufficient-signal",
348
+ "evidence": blob_probe[:200],
349
+ "action": _ACTIONS[UNKNOWN],
350
+ "confidence": "low",
351
+ }
352
+
353
+
354
+ def explain(engine_id: str, *, spec: dict[str, Any] | None = None,
355
+ error: BaseException | None = None,
356
+ status_code: int | None = None,
357
+ output: str | None = None,
358
+ anti_bot: bool | None = None) -> dict[str, Any]:
359
+ """引擎级便捷入口:自动带上该引擎已声明的依赖/密钥缺失事实再归类。"""
360
+ spec = spec or {}
361
+ missing_deps: list[dict[str, Any]] = []
362
+ missing_env: list[str] = []
363
+ try:
364
+ from engine_requires import requires_status
365
+ missing_deps = requires_status(spec).get("missing_deps") or []
366
+ except Exception:
367
+ pass
368
+ try:
369
+ from engine_env import missing_env_for
370
+ missing_env = missing_env_for(engine_id, spec) or []
371
+ except Exception:
372
+ pass
373
+ res = classify(error=error, status_code=status_code, output=output,
374
+ missing_deps=missing_deps, missing_env=missing_env,
375
+ anti_bot=anti_bot)
376
+ res["engine_id"] = engine_id
377
+ return res
378
+
379
+
380
+ def from_note(note: dict[str, Any] | None,
381
+ engine_id: str = "") -> dict[str, Any]:
382
+ """把归因寄存器里的一条记录规整成与 classify 同构的归因契约。
383
+
384
+ 寄存器(engines_base.note_failure)存的是 {category, reason, detail, ts},
385
+ 而 classify/explain 输出 {category, reason, evidence, action, confidence}。
386
+ 熔断持久化与 --list-engines 展示都用后一形态,这里做一次转换,避免每个
387
+ 消费者各自拼字段(字段名漂移过一次就会让「为什么坏」显示不出东西)。
388
+ """
389
+ note = note or {}
390
+ category = str(note.get("category") or UNKNOWN)
391
+ reason = str(note.get("reason") or "")
392
+ # confidence 不newly invent:按 reason 前缀还原现场判定的把握度
393
+ # (http-<code> 来自状态码→high;text: 来自文本模式→medium;
394
+ # insufficient-signal/空→low)。一律报 high 会把 unknown 也标成高置信,
395
+ # 违背本模块「信息不足不硬猜」的纪律。
396
+ if not note.get("category"):
397
+ confidence = "low"
398
+ elif reason.startswith("http-"):
399
+ confidence = "high"
400
+ elif reason.startswith("text:") or reason == "insufficient-signal":
401
+ confidence = "medium" if reason.startswith("text:") else "low"
402
+ else:
403
+ confidence = "medium"
404
+ return {
405
+ "category": category,
406
+ "reason": reason,
407
+ "evidence": str(note.get("detail") or "")[:200],
408
+ "action": _ACTIONS.get(category, _ACTIONS[UNKNOWN]),
409
+ "confidence": confidence,
410
+ "engine_id": engine_id,
411
+ }