argo-search 1.0.1 → 2.9.8

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 (472) hide show
  1. package/LICENSE +201 -21
  2. package/README.en.md +735 -0
  3. package/README.es.md +777 -0
  4. package/README.ja.md +777 -0
  5. package/README.ko.md +777 -0
  6. package/README.md +778 -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/why-better.svg +104 -0
  12. package/assets/readme/workflow.svg +83 -0
  13. package/backends/domain_profiles.json +2356 -96
  14. package/backends/engine_registry.yaml +3428 -503
  15. package/backends/query_synonyms_cn.json +35 -0
  16. package/backends/quota_profiles.json +2488 -160
  17. package/backends/source_types_cn.json +109 -0
  18. package/backends/text_lexicon.json +44 -0
  19. package/bin/argo +772 -0
  20. package/bin/argo.js +102 -39
  21. package/config.yaml +5139 -367
  22. package/cordis.patch.yml +21 -0
  23. package/data/countries.json +40 -0
  24. package/data/lang_matrix/lang_capability.json +842 -0
  25. package/data/lang_matrix/matrix_2026-09-10.json +11921 -0
  26. package/data/regions_cn.json +1 -0
  27. package/docs/ADDING_NEW_ENGINE.md +184 -0
  28. package/docs/ARGO_INTRO.md +124 -0
  29. package/docs/DATA_SOURCE_GAPS.md +81 -0
  30. package/docs/DESIGN_LOCAL_DATA_FUSION.md +90 -0
  31. package/docs/ENGINE_CATALOG.md +575 -0
  32. package/docs/MCP_SETUP.md +108 -0
  33. package/docs/PLATFORM_PATHS.md +111 -0
  34. package/docs/RELEASE_NOTES_v2.8.0.md +71 -0
  35. package/docs/RELEASE_NOTES_v2.8.2.md +63 -0
  36. package/docs/RELEASE_NOTES_v2.8.3.md +55 -0
  37. package/docs/RELEASE_NOTES_v2.8.4.md +79 -0
  38. package/docs/RELEASE_NOTES_v2.8.5.md +102 -0
  39. package/docs/RELEASE_NOTES_v2.8.6.md +66 -0
  40. package/docs/RELEASE_NOTES_v2.8.7.md +65 -0
  41. package/docs/RELEASE_NOTES_v2.8.8.md +67 -0
  42. package/docs/RELEASE_NOTES_v2.8.9.md +67 -0
  43. package/docs/RELEASE_NOTES_v2.9.0.md +64 -0
  44. package/docs/RELEASE_NOTES_v2.9.8.md +73 -0
  45. package/docs/SEARCH_ARCHIVE.md +115 -0
  46. package/docs/assets/architecture.svg +104 -0
  47. package/docs/assets/hero.svg +98 -0
  48. package/docs/engines/bangumi.md +27 -0
  49. package/docs/engines/biorxiv.md +27 -0
  50. package/docs/engines/clawhub.md +27 -0
  51. package/docs/engines/crt_sh.md +27 -0
  52. package/docs/engines/datacite.md +27 -0
  53. package/docs/engines/deps_dev.md +27 -0
  54. package/docs/engines/douban_movie.md +27 -0
  55. package/docs/engines/endoflife.md +27 -0
  56. package/docs/engines/flk_law.md +27 -0
  57. package/docs/engines/fxtwitter.md +27 -0
  58. package/docs/engines/google_news.md +27 -0
  59. package/docs/engines/gov_regulations.md +27 -0
  60. package/docs/engines/guqian.md +27 -0
  61. package/docs/engines/hackernews.md +27 -0
  62. package/docs/engines/iplant.md +27 -0
  63. package/docs/engines/keenable.md +27 -0
  64. package/docs/engines/met_museum.md +27 -0
  65. package/docs/engines/nasa_images.md +27 -0
  66. package/docs/engines/netease_music.md +27 -0
  67. package/docs/engines/npm.md +27 -0
  68. package/docs/engines/nvd.md +27 -0
  69. package/docs/engines/openreview.md +27 -0
  70. package/docs/engines/openstd.md +27 -0
  71. package/docs/engines/parallel_free.md +27 -0
  72. package/docs/engines/people_daily.md +27 -0
  73. package/docs/engines/realtime_index.md +27 -0
  74. package/docs/engines/sec_edgar.md +27 -0
  75. package/docs/engines/seltz.md +27 -0
  76. package/docs/engines/skillsmp.md +27 -0
  77. package/docs/engines/sspai.md +27 -0
  78. package/docs/engines/std_samr.md +27 -0
  79. package/docs/engines/train.md +27 -0
  80. package/docs/engines/un_comtrade.md +27 -0
  81. package/docs/engines/wikisource.md +27 -0
  82. package/docs/engines/zdic.md +27 -0
  83. package/docs/engines/zenodo.md +27 -0
  84. package/docs/engines/zhihu_hot_app.md +27 -0
  85. package/docs//344/270/272/344/273/200/344/271/210/351/200/211/346/213/251argo.md +176 -0
  86. package/engines/README.md +10 -0
  87. package/engines/_template_cli.yaml +39 -0
  88. package/engines/_template_http.yaml +37 -0
  89. package/engines/plugins/_template_plugin.py +50 -0
  90. package/engines/specs/_cisa_kev.yaml +54 -0
  91. package/engines/specs/_osv.yaml +63 -0
  92. package/engines/specs/aljazeera.yaml +43 -0
  93. package/engines/specs/antara.yaml +43 -0
  94. package/engines/specs/artic.yaml +20 -0
  95. package/engines/specs/aviation_weather.yaml +39 -0
  96. package/engines/specs/bangumi.yaml +21 -0
  97. package/engines/specs/biorxiv.yaml +24 -0
  98. package/engines/specs/carbon_intensity.yaml +32 -0
  99. package/engines/specs/cfets.yaml +41 -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/defillama.yaml +38 -0
  113. package/engines/specs/deps_dev.yaml +21 -0
  114. package/engines/specs/digup.yaml +36 -0
  115. package/engines/specs/doi.yaml +39 -0
  116. package/engines/specs/douban_movie.yaml +22 -0
  117. package/engines/specs/dw_news.yaml +47 -0
  118. package/engines/specs/egov_law.yaml +21 -0
  119. package/engines/specs/elpais.yaml +43 -0
  120. package/engines/specs/endoflife.yaml +21 -0
  121. package/engines/specs/energy_charts.yaml +21 -0
  122. package/engines/specs/factcheck_org.yaml +52 -0
  123. package/engines/specs/faz.yaml +43 -0
  124. package/engines/specs/federal_register.yaml +57 -0
  125. package/engines/specs/firecrawl.yaml +53 -0
  126. package/engines/specs/flk_law.yaml +24 -0
  127. package/engines/specs/folha.yaml +43 -0
  128. package/engines/specs/france24.yaml +44 -0
  129. package/engines/specs/full_fact.yaml +47 -0
  130. package/engines/specs/fxtwitter.yaml +36 -0
  131. package/engines/specs/gbfs_nyc.yaml +32 -0
  132. package/engines/specs/gdacs.yaml +21 -0
  133. package/engines/specs/gdelt.yaml +64 -0
  134. package/engines/specs/gleif.yaml +55 -0
  135. package/engines/specs/google_news.yaml +22 -0
  136. package/engines/specs/gov_regulations.yaml +38 -0
  137. package/engines/specs/guardian_rss.yaml +59 -0
  138. package/engines/specs/hkex.yaml +40 -0
  139. package/engines/specs/hurriyet.yaml +43 -0
  140. package/engines/specs/iplant.yaml +25 -0
  141. package/engines/specs/jikan.yaml +24 -0
  142. package/engines/specs/jolpica.yaml +20 -0
  143. package/engines/specs/k10plus.yaml +20 -0
  144. package/engines/specs/keenable.yaml +44 -0
  145. package/engines/specs/keenable_free.yaml +36 -0
  146. package/engines/specs/lefigaro.yaml +43 -0
  147. package/engines/specs/listenbrainz.yaml +19 -0
  148. package/engines/specs/matichon.yaml +43 -0
  149. package/engines/specs/met_museum.yaml +21 -0
  150. package/engines/specs/nasa_images.yaml +45 -0
  151. package/engines/specs/netease_music.yaml +38 -0
  152. package/engines/specs/nhk.yaml +43 -0
  153. package/engines/specs/nhtsa_vpic.yaml +20 -0
  154. package/engines/specs/noaa_swpc.yaml +20 -0
  155. package/engines/specs/nvd.yaml +38 -0
  156. package/engines/specs/obis.yaml +20 -0
  157. package/engines/specs/opencitations.yaml +52 -0
  158. package/engines/specs/openf1.yaml +21 -0
  159. package/engines/specs/openfoodfacts.yaml +45 -0
  160. package/engines/specs/openligadb.yaml +20 -0
  161. package/engines/specs/openreview.yaml +37 -0
  162. package/engines/specs/openstd.yaml +21 -0
  163. package/engines/specs/people_daily.yaml +22 -0
  164. package/engines/specs/realtime_index.yaml +34 -0
  165. package/engines/specs/ror.yaml +20 -0
  166. package/engines/specs/satnogs.yaml +20 -0
  167. package/engines/specs/sec_edgar.yaml +46 -0
  168. package/engines/specs/shfe.yaml +39 -0
  169. package/engines/specs/skillsmp.yaml +50 -0
  170. package/engines/specs/sogou_weixin_browser.yaml +30 -0
  171. package/engines/specs/soilgrids.yaml +25 -0
  172. package/engines/specs/sspai.yaml +36 -0
  173. package/engines/specs/stackexchange.yaml +46 -0
  174. package/engines/specs/std_samr.yaml +21 -0
  175. package/engines/specs/tass.yaml +43 -0
  176. package/engines/specs/tavily_free.yaml +56 -0
  177. package/engines/specs/tle_mirror.yaml +21 -0
  178. package/engines/specs/train.yaml +37 -0
  179. package/engines/specs/tvmaze.yaml +20 -0
  180. package/engines/specs/twitter_syndication.yaml +31 -0
  181. package/engines/specs/un_comtrade.yaml +23 -0
  182. package/engines/specs/unpaywall.yaml +54 -0
  183. package/engines/specs/vnpress.yaml +43 -0
  184. package/engines/specs/weather.yaml +32 -0
  185. package/engines/specs/who_don.yaml +21 -0
  186. package/engines/specs/who_gho.yaml +20 -0
  187. package/engines/specs/wikimedia_commons.yaml +34 -0
  188. package/engines/specs/wikisource.yaml +22 -0
  189. package/engines/specs/worms.yaml +19 -0
  190. package/engines/specs/x_trending.yaml +34 -0
  191. package/engines/specs/yna.yaml +43 -0
  192. package/engines/specs/ynet.yaml +43 -0
  193. package/engines/specs/yuanbao.yaml +93 -0
  194. package/engines/specs/zbmath.yaml +40 -0
  195. package/engines/specs/zdic.yaml +22 -0
  196. package/engines/specs/zenodo.yaml +27 -0
  197. package/engines/specs/zhihu_hot_app.yaml +35 -0
  198. package/mcp/clients.yaml +106 -0
  199. package/package.json +55 -12
  200. package/packages/dsh-plugin/README.md +152 -0
  201. package/packages/dsh-plugin/cordis.patch.yml +48 -0
  202. package/packages/dsh-plugin/dsh/client.js +1533 -0
  203. package/packages/dsh-plugin/dsh/diagnostics.js +54 -0
  204. package/packages/dsh-plugin/dsh/index.js +527 -0
  205. package/packages/dsh-plugin/dsh/native-tools.mjs +749 -0
  206. package/packages/dsh-plugin/dsh/runner.js +666 -0
  207. package/packages/dsh-plugin/dsh/wide-research.js +878 -0
  208. package/packages/dsh-plugin/package.json +38 -0
  209. package/packages/dsh-plugin/scripts/sync-local.sh +70 -0
  210. package/packages/dsh-plugin/test/client.test.js +406 -0
  211. package/packages/dsh-plugin/test/config.test.js +30 -0
  212. package/packages/dsh-plugin/test/diagnostics.test.js +28 -0
  213. package/packages/dsh-plugin/test/index.test.js +1382 -0
  214. package/references/query-templates.md +96 -0
  215. package/references/query-templates.yaml +118 -0
  216. package/scripts/ab_eval.py +219 -0
  217. package/scripts/ab_eval_p0p1.py +266 -0
  218. package/scripts/adaptive.py +294 -70
  219. package/scripts/answer.py +154 -0
  220. package/scripts/archive_run.py +591 -0
  221. package/scripts/argo_engine_registry.py +172 -0
  222. package/scripts/argo_paths.py +728 -0
  223. package/scripts/article.py +136 -0
  224. package/scripts/article_meta.py +131 -0
  225. package/scripts/arxiv_source.py +201 -0
  226. package/scripts/badcase_ledger.py +252 -0
  227. package/scripts/batch_probe.py +241 -0
  228. package/scripts/benchmark.py +19 -0
  229. package/scripts/bounded_run.py +144 -0
  230. package/scripts/browser_auth.py +323 -0
  231. package/scripts/budget.py +247 -0
  232. package/scripts/budget_cli.py +93 -0
  233. package/scripts/build_release_assets.sh +65 -0
  234. package/scripts/burstiness_detector.py +147 -0
  235. package/scripts/cache.py +1066 -67
  236. package/scripts/cache_guard.py +271 -0
  237. package/scripts/cache_key_vdom.py +56 -0
  238. package/scripts/cache_similarity.py +170 -0
  239. package/scripts/caliber_isolation.py +195 -0
  240. package/scripts/calibrate_lowquality.py +210 -0
  241. package/scripts/candidate_envelope.py +366 -0
  242. package/scripts/chrome_cdp.py +871 -0
  243. package/scripts/ci_drift_gate.py +90 -0
  244. package/scripts/circuit_breaker.py +389 -0
  245. package/scripts/citations.py +334 -0
  246. package/scripts/cite_cli.py +59 -0
  247. package/scripts/cjk_tokens.py +95 -0
  248. package/scripts/clarify.py +47 -24
  249. package/scripts/cli_io.py +240 -0
  250. package/scripts/config.py +683 -45
  251. package/scripts/config_cache.py +402 -0
  252. package/scripts/conn_pool.py +220 -0
  253. package/scripts/content_boundary.py +46 -0
  254. package/scripts/content_security.py +685 -0
  255. package/scripts/content_signals.py +751 -0
  256. package/scripts/crawl.py +74 -35
  257. package/scripts/cross_lingual_trace.py +293 -0
  258. package/scripts/daemon.py +866 -0
  259. package/scripts/digup_bridge.py +214 -0
  260. package/scripts/dispatch_result.py +98 -0
  261. package/scripts/engine_admission.py +366 -0
  262. package/scripts/engine_dispatch.py +982 -0
  263. package/scripts/engine_env.py +539 -0
  264. package/scripts/engine_failure.py +411 -0
  265. package/scripts/engine_families.py +738 -0
  266. package/scripts/engine_policy.py +218 -0
  267. package/scripts/engine_requires.py +190 -0
  268. package/scripts/engine_status.py +322 -0
  269. package/scripts/engine_validate.py +638 -0
  270. package/scripts/engines.py +799 -294
  271. package/scripts/engines_base.py +1521 -0
  272. package/scripts/engines_builders.py +310 -0
  273. package/scripts/engines_builders_batch10.py +204 -0
  274. package/scripts/engines_builders_batch11.py +174 -0
  275. package/scripts/engines_builders_batch12.py +103 -0
  276. package/scripts/engines_builders_batch13.py +340 -0
  277. package/scripts/engines_builders_batch14.py +656 -0
  278. package/scripts/engines_builders_batch15.py +249 -0
  279. package/scripts/engines_builders_batch9.py +1468 -0
  280. package/scripts/engines_builders_cn.py +2283 -0
  281. package/scripts/engines_builders_data.py +2923 -0
  282. package/scripts/engines_builders_data_macro.py +775 -0
  283. package/scripts/engines_builders_feeds.py +255 -0
  284. package/scripts/engines_builders_intl.py +1239 -0
  285. package/scripts/engines_builders_keyless.py +111 -0
  286. package/scripts/engines_builders_search.py +440 -0
  287. package/scripts/engines_builders_tech.py +1359 -0
  288. package/scripts/evidence.py +620 -166
  289. package/scripts/evidence_loop.py +624 -0
  290. package/scripts/evidence_tier.py +298 -0
  291. package/scripts/except_sets.py +25 -0
  292. package/scripts/extract.py +55 -16
  293. package/scripts/fact_align.py +207 -0
  294. package/scripts/fact_crosscheck.py +230 -0
  295. package/scripts/fetch.py +25 -12
  296. package/scripts/fetch_browser.py +87 -0
  297. package/scripts/fetch_jsrun.py +122 -0
  298. package/scripts/fetch_quality.py +225 -0
  299. package/scripts/fetch_render_tinyfish.py +117 -0
  300. package/scripts/fetch_v3.py +1804 -0
  301. package/scripts/focus_extract.py +350 -0
  302. package/scripts/fulltext_store.py +169 -0
  303. package/scripts/fxtwitter_api.py +325 -0
  304. package/scripts/gen_engine_catalog.py +364 -0
  305. package/scripts/gen_native_tools.py +91 -0
  306. package/scripts/gen_routing_snapshot.py +195 -0
  307. package/scripts/health_check.py +140 -402
  308. package/scripts/health_probe.py +23 -8
  309. package/scripts/hot_state.py +134 -0
  310. package/scripts/http_client.py +1053 -0
  311. package/scripts/image_ops.py +430 -0
  312. package/scripts/image_vision/vision_probe.swift +126 -0
  313. package/scripts/install.ps1 +166 -0
  314. package/scripts/install.sh +221 -0
  315. package/scripts/job.py +1186 -0
  316. package/scripts/jump_resolver.py +235 -0
  317. package/scripts/lang_capability.py +150 -0
  318. package/scripts/lang_detect.py +289 -0
  319. package/scripts/lang_matrix_probe.py +329 -0
  320. package/scripts/lang_pref.py +311 -0
  321. package/scripts/link_source.py +340 -0
  322. package/scripts/local_image.py +970 -0
  323. package/scripts/local_seek.py +402 -0
  324. package/scripts/macro_countries.py +97 -0
  325. package/scripts/matrix_search_eval.py +1187 -0
  326. package/scripts/mcp_compact.py +234 -0
  327. package/scripts/mcp_diag.py +8 -3
  328. package/scripts/mcp_handlers.py +492 -0
  329. package/scripts/mcp_handlers_surface.py +157 -0
  330. package/scripts/mcp_launch.sh +124 -0
  331. package/scripts/mcp_local.py +241 -0
  332. package/scripts/mcp_server.py +125 -419
  333. package/scripts/mcp_setup.py +431 -0
  334. package/scripts/mcp_tools.py +331 -0
  335. package/scripts/mcp_transport.py +191 -0
  336. package/scripts/mcp_warm.py +127 -0
  337. package/scripts/min_version_scan.py +335 -0
  338. package/scripts/net_proxy.py +258 -0
  339. package/scripts/network_aware.py +152 -0
  340. package/scripts/output_transparency.py +200 -0
  341. package/scripts/paid_policy.py +98 -0
  342. package/scripts/paper.py +274 -0
  343. package/scripts/pdf_extract.py +518 -0
  344. package/scripts/phrase_filter.py +66 -0
  345. package/scripts/plan.py +422 -0
  346. package/scripts/postprocess_signals.py +150 -0
  347. package/scripts/pre-commit +48 -0
  348. package/scripts/query_enhance.py +157 -0
  349. package/scripts/query_operators.py +196 -0
  350. package/scripts/query_rewriter.py +116 -7
  351. package/scripts/query_signals.py +300 -0
  352. package/scripts/query_templates.py +167 -0
  353. package/scripts/query_understanding.py +411 -0
  354. package/scripts/query_variants.py +298 -0
  355. package/scripts/quota.py +633 -76
  356. package/scripts/rank_signals.py +775 -0
  357. package/scripts/ranking_eval.py +319 -0
  358. package/scripts/readability_extract.py +433 -0
  359. package/scripts/recompute.py +415 -0
  360. package/scripts/recovery.py +616 -0
  361. package/scripts/recovery_l0.py +160 -0
  362. package/scripts/recovery_runner.py +150 -0
  363. package/scripts/redskill/redskill_engine.py +332 -0
  364. package/scripts/regression_p0p1.py +318 -0
  365. package/scripts/replay_eval.py +658 -0
  366. package/scripts/rerank_tfidf.py +225 -0
  367. package/scripts/research.py +607 -403
  368. package/scripts/research_cli.py +361 -0
  369. package/scripts/research_dossier.py +492 -0
  370. package/scripts/research_expand.py +169 -0
  371. package/scripts/research_gates.py +272 -0
  372. package/scripts/research_report.py +209 -0
  373. package/scripts/research_strategy.py +37 -0
  374. package/scripts/research_work_packages.py +195 -0
  375. package/scripts/result_lang.py +311 -0
  376. package/scripts/retry_policy.py +76 -0
  377. package/scripts/robots_guard.py +259 -0
  378. package/scripts/route.py +921 -254
  379. package/scripts/route_bangs.py +40 -0
  380. package/scripts/route_cache.py +243 -0
  381. package/scripts/route_combo.py +917 -0
  382. package/scripts/route_domains.py +341 -0
  383. package/scripts/route_lang.py +605 -0
  384. package/scripts/route_log.py +63 -0
  385. package/scripts/route_policy.py +250 -0
  386. package/scripts/rrf_classic.py +66 -0
  387. package/scripts/screenshot.py +73 -0
  388. package/scripts/search.py +886 -406
  389. package/scripts/search_attribution.py +185 -0
  390. package/scripts/search_benchmark.py +407 -0
  391. package/scripts/search_cli.py +640 -0
  392. package/scripts/search_entry.py +395 -0
  393. package/scripts/search_output.py +690 -0
  394. package/scripts/search_pipeline.py +926 -0
  395. package/scripts/search_rank.py +991 -0
  396. package/scripts/search_types.py +129 -16
  397. package/scripts/seek_locator.py +68 -0
  398. package/scripts/semantic_evidence.py +391 -0
  399. package/scripts/serp_guard.py +336 -0
  400. package/scripts/serp_kill_log.py +74 -0
  401. package/scripts/single_flight.py +120 -0
  402. package/scripts/social_engines/__init__.py +10 -0
  403. package/scripts/social_engines/bilibili_engine.py +131 -0
  404. package/scripts/social_engines/hackernews_engine.py +113 -0
  405. package/scripts/social_engines/reddit_engine.py +172 -0
  406. package/scripts/social_engines/twitter_engine.py +397 -0
  407. package/scripts/social_engines/v2ex_engine.py +101 -0
  408. package/scripts/social_engines/weibo_engine.py +128 -0
  409. package/scripts/social_engines/xiaohongshu_engine.py +137 -0
  410. package/scripts/social_engines/zhihu_engine.py +139 -0
  411. package/scripts/social_research.py +201 -0
  412. package/scripts/sogou_weixin_browser.py +318 -0
  413. package/scripts/source_ledger.py +249 -0
  414. package/scripts/stage_timing.py +58 -0
  415. package/scripts/stats_cli.py +107 -0
  416. package/scripts/straggler_policy.py +60 -0
  417. package/scripts/stylometry_detector.py +231 -0
  418. package/scripts/sync_backends.py +353 -0
  419. package/scripts/sync_installs.py +29 -0
  420. package/scripts/template_cli.py +127 -0
  421. package/scripts/text_lexicon.py +72 -0
  422. package/scripts/tfidf_router.py +109 -37
  423. package/scripts/time_utils.py +233 -0
  424. package/scripts/topic_research_profiles.py +643 -0
  425. package/scripts/train.py +737 -0
  426. package/scripts/tweet.py +596 -0
  427. package/scripts/url_canon.py +217 -0
  428. package/scripts/url_optimize.py +56 -0
  429. package/scripts/url_safety.py +236 -0
  430. package/scripts/usage_log.py +116 -0
  431. package/scripts/usage_log_clean.py +113 -0
  432. package/scripts/v2ex_nodes.py +311 -0
  433. package/scripts/variant_recall.py +188 -0
  434. package/scripts/watch.py +205 -0
  435. package/scripts/wechat_article.py +258 -0
  436. package/scripts/wide_research.py +447 -0
  437. package/scripts/wx.py +349 -0
  438. package/scripts/x_article_fetch.py +141 -0
  439. package/scripts/x_search.py +234 -0
  440. package/scripts/x_trending.py +189 -0
  441. package/scripts/yaml_load.py +67 -0
  442. package/scripts/zhihu_quota.py +139 -0
  443. package/sub-skills/ego-search/SKILL.md +253 -0
  444. package/sub-skills/ego-search/scripts/ego_search.py +800 -0
  445. package/sub-skills/ego-search/scripts/merge.py +226 -0
  446. package/sub-skills/ego-search/scripts/quality.py +64 -0
  447. package/sub-skills/ego-search/scripts/runtime.py +172 -0
  448. package/sub-skills/ego-search/scripts/safety.py +109 -0
  449. package/sub-skills/ego-search/scripts/serp_spec.py +109 -0
  450. package/sub-skills/ego-search/scripts/webbridge_adapter.py +374 -0
  451. package/sub-skills/js-run/SKILL.md +67 -0
  452. package/sub-skills/js-run/scripts/jsrun.py +112 -0
  453. package/sub-skills/js-run/scripts/shim.js +188 -0
  454. package/sub-skills/local-search/SKILL.md +50 -53
  455. package/sub-skills/local-search/bm25.py +186 -0
  456. package/sub-skills/local-search/cli_runner.py +331 -0
  457. package/sub-skills/local-search/config.yaml +152 -55
  458. package/sub-skills/local-search/engine_registry.py +91 -26
  459. package/sub-skills/local-search/{health_check.py → local_health_check.py} +140 -10
  460. package/sub-skills/local-search/local_search_adapter.py +13 -2
  461. package/sub-skills/local-search/parse_maps.yaml +40 -42
  462. package/sub-skills/local-search/parsers.py +328 -0
  463. package/sub-skills/local-search/search_v3.py +716 -242
  464. package/sub-skills/local-search/smart_router.py +47 -7
  465. package/sub-skills/local-seek/SKILL.md +110 -0
  466. package/sub-skills/local-seek/config/domains.yaml +20 -0
  467. package/sub-skills/local-seek/scripts/eval_rank.py +216 -0
  468. package/sub-skills/local-seek/scripts/eval_seek.py +224 -0
  469. package/sub-skills/local-seek/scripts/seek.py +1465 -0
  470. package/sub-skills/local-seek/scripts/seek_frecency.py +126 -0
  471. package/sub-skills/local-seek/scripts/seek_fts.py +430 -0
  472. package/sub-skills/local-seek/scripts/seek_rank.py +197 -0
@@ -0,0 +1,431 @@
1
+ #!/usr/bin/env python3
2
+ """mcp_setup.py — Argo 多客户端 MCP 一键注入/诊断/还原(自研,零第三方依赖)
3
+
4
+ 设计保持一致 Argo 唯一来源哲学(config.yaml / engines/specs/*.yaml):
5
+ - 客户端描述来源 = mcp/clients.yaml(改客户端不改代码;加一行 YAML 即可)
6
+ - PHP/Python 均为 stdlib,不引入 tomlkit/toml 等第三方依赖
7
+
8
+ 安全与可逆(借鉴分布式系统写入范式,而非复制任何外部代码):
9
+ - atomic_write:同目录临时文件 + os.replace,并发读者只见旧或新,绝无半截
10
+ - 备份:写入前 COPY 原文件到 ~/.argo/mcp-backup/<ts>-<client>.<ext>,可回滚
11
+ - 权限:含密钥的配置文件以 0600 写入
12
+ - --dry-run:只预览不写;--undo:精确移除 entry 或从备份回滚
13
+ - JSON patch 保留未改动子树原文;TOML 走"行级 append section"不动已有内容
14
+
15
+ 用法:
16
+ python3 scripts/mcp_setup.py status # 诊断各客户端
17
+ python3 scripts/mcp_setup.py inject --all # 注入所有已安装
18
+ python3 scripts/mcp_setup.py inject --claude-code # 注入指定
19
+ python3 scripts/mcp_setup.py inject --all --dry-run # 预览
20
+ python3 scripts/mcp_setup.py undo --all # 还原
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import argparse
26
+ import json
27
+ import os
28
+ import shutil
29
+ import sys
30
+ from datetime import datetime
31
+ from cli_io import dumps_pretty
32
+ from pathlib import Path
33
+ from typing import Any
34
+
35
+ try:
36
+ import yaml # pyyaml(Argo 已有依赖)
37
+ except ImportError: # pragma: no cover
38
+ yaml = None
39
+
40
+ ENTRY_NAME = "argo"
41
+
42
+
43
+ def _backup_dir() -> Path:
44
+ # 备份目录跟随 home(ARGO_HOME_OVERRIDE 隔离时也隔离),保证 e2e/测试不污染真实 ~/.argo
45
+ return _home() / ".argo" / "mcp-backup"
46
+
47
+
48
+ # ── 来源加载 ──────────────────────────────────────────────────────────────
49
+
50
+ def _clients_file() -> Path:
51
+ override = os.environ.get("ARGO_CLIENTS_PATH", "").strip()
52
+ if override:
53
+ return Path(override).expanduser()
54
+ return Path(__file__).resolve().parent.parent / "mcp" / "clients.yaml"
55
+
56
+
57
+ def load_clients() -> list[dict[str, Any]]:
58
+ """读取 mcp/clients.yaml(声明式来源)。读取失败抛异常(fail-loud)。"""
59
+ path = _clients_file()
60
+ if not path.exists():
61
+ raise FileNotFoundError(f"客户端真源不存在: {path}")
62
+ if yaml is None:
63
+ raise RuntimeError("需要 pyyaml(Argo 已有依赖)")
64
+ from yaml_load import load as _yaml_load
65
+ data = _yaml_load(path) or {}
66
+ clients = data.get("clients") or []
67
+ if not isinstance(clients, list) or not clients:
68
+ raise ValueError(f"clients.yaml 缺少 clients 列表: {path}")
69
+ return clients
70
+
71
+
72
+ def _home() -> Path:
73
+ # 保持一致 install.sh 的 HOME 解析;KEENABLE 式 HOME 覆盖便于 e2e 隔离,但用 Argo 自有名
74
+ override = os.environ.get("ARGO_HOME_OVERRIDE", "").strip()
75
+ home = Path(override).expanduser() if override else Path.home()
76
+ return home
77
+
78
+
79
+ def _resolve(path_str: str) -> Path:
80
+ """解析相对 home 或绝对路径; 支持 {home} 占位。"""
81
+ s = path_str.strip()
82
+ if s.startswith("{home}"):
83
+ s = s.replace("{home}", str(_home()), 1)
84
+ p = Path(s).expanduser()
85
+ if not p.is_absolute():
86
+ p = _home() / p
87
+ return p
88
+
89
+
90
+ def _client_config_path(client: dict[str, Any]) -> str:
91
+ """获取当前操作系统对应的配置文件路径声明。"""
92
+ plat = sys.platform
93
+ if plat == "darwin" and "config_path_darwin" in client:
94
+ return client["config_path_darwin"]
95
+ if plat == "win32" and "config_path_win32" in client:
96
+ return client["config_path_win32"]
97
+ if plat.startswith("linux") and "config_path_linux" in client:
98
+ return client["config_path_linux"]
99
+ return client.get("config_path", "")
100
+
101
+
102
+ def _client_detects(client: dict[str, Any]) -> list[str]:
103
+ """获取当前操作系统对应的客户端探测路径列表。"""
104
+ plat = sys.platform
105
+ if plat == "darwin" and "detect_darwin" in client:
106
+ return client["detect_darwin"]
107
+ if plat == "win32" and "detect_win32" in client:
108
+ return client["detect_win32"]
109
+ if plat.startswith("linux") and "detect_linux" in client:
110
+ return client["detect_linux"]
111
+ return client.get("detect") or []
112
+
113
+
114
+ def detect(client: dict[str, Any]) -> bool:
115
+ """客户端是否已安装(detect 路径任一存在)。无 detect 字段则看 config_path 父目录。"""
116
+ detects = _client_detects(client)
117
+ if detects:
118
+ return any(_resolve(d).exists() for d in detects)
119
+ return _resolve(_client_config_path(client)).parent.exists()
120
+
121
+
122
+ # ── MCP 命令模板 ────────────────────────────────────────────────────────
123
+
124
+ def _mcp_command(client: dict[str, Any]) -> dict[str, Any]:
125
+ """生成该客户端应写入的 argo MCP entry(stdio 命令 + 可选 env)。
126
+
127
+ v2.8.5 起 command 指向 mcp_launch.sh 启动器而非 python 直启:
128
+ 启动器负责注入引擎密钥(~/.config/argo/env 唯一来源 + launchctl 保底),
129
+ 任何客户端/启动上下文行为一致——密钥配置一次,处处生效。
130
+ """
131
+ install_dir = Path(__file__).resolve().parent.parent
132
+ launcher = install_dir / "scripts" / "mcp_launch.sh"
133
+ return {
134
+ "command": str(launcher),
135
+ "args": [],
136
+ "env": {"PYTHONIOENCODING": "utf-8"},
137
+ }
138
+
139
+
140
+ # ── 备份 ────────────────────────────────────────────────────────────────
141
+
142
+ def backup_file(path: Path) -> Path | None:
143
+ """写入前备份原文件(带时间戳)。成功返回备份路径,原文件不存在返回 None。"""
144
+ if not path.exists():
145
+ return None
146
+ backup_dir = _backup_dir()
147
+ backup_dir.mkdir(parents=True, exist_ok=True)
148
+ ts = datetime.now().strftime("%Y%m%dT%H%M%S")
149
+ backup = backup_dir / f"{ts}_{path.name}"
150
+ shutil.copy2(path, backup)
151
+ return backup
152
+
153
+
154
+ def list_backups(file_name: str) -> list[Path]:
155
+ """列出某配置文件的所有历史备份(按时间倒序)。"""
156
+ backup_dir = _backup_dir()
157
+ if not backup_dir.exists():
158
+ return []
159
+ return sorted(
160
+ (p for p in backup_dir.glob(f"*_{file_name}") if p.is_file()),
161
+ key=lambda p: p.name,
162
+ reverse=True,
163
+ )
164
+
165
+
166
+ # ── 原子写 ──────────────────────────────────────────────────────────────
167
+
168
+ def atomic_write(path: Path, content: str, secret: bool = False) -> None:
169
+ """原子写文本(薄转发到 argo_paths 唯一来源)。含密钥时 0600 权限。
170
+
171
+ 本函数曾自带一份 mkstemp + replace 实现,与 argo_paths.atomic_write_text
172
+ 逐行重复;收紧到来源后,唯一 tmp 名/失败清理等不变量只有一处维护。
173
+ """
174
+ import argo_paths
175
+ argo_paths.atomic_write_text(path, content, mode=0o600 if secret else None)
176
+
177
+
178
+ # ── JSON patch(保留未改动子树原文)──────────────────────────────────────
179
+
180
+ def _json_read(path: Path) -> dict[str, Any]:
181
+ """读取 JSON 配置。缺失=空 dict;存在但非法=抛异常(fail-loud,不覆盖用户文件)。"""
182
+ if not path.exists():
183
+ return {}
184
+ try:
185
+ data = json.loads(path.read_text(encoding="utf-8"))
186
+ except json.JSONDecodeError as e:
187
+ raise ValueError(f"配置非法 JSON(未修改): {path}: {e}") from e
188
+ if not isinstance(data, dict):
189
+ raise ValueError(f"配置根非对象(未修改): {path}")
190
+ return data
191
+
192
+
193
+ def _inject_json(client: dict[str, Any], entry: dict[str, Any]) -> str:
194
+ """JSON 客户端注入:合并 entry,保留未改动子树。"""
195
+ path = _resolve(_client_config_path(client))
196
+ config = _json_read(path)
197
+ servers_key = client["servers_key"]
198
+ if not isinstance(config.get(servers_key), dict):
199
+ config[servers_key] = {}
200
+ config[servers_key][ENTRY_NAME] = entry
201
+ return dumps_pretty(config) + "\n"
202
+
203
+
204
+ def _remove_json(client: dict[str, Any]) -> str | None:
205
+ """JSON 客户端移除 argo entry。返回新内容;无 entry 返回 None。"""
206
+ path = _resolve(_client_config_path(client))
207
+ if not path.exists():
208
+ return None
209
+ config = _json_read(path)
210
+ servers = config.get(client["servers_key"])
211
+ if isinstance(servers, dict) and ENTRY_NAME in servers:
212
+ del servers[ENTRY_NAME]
213
+ return dumps_pretty(config) + "\n"
214
+ return None
215
+
216
+
217
+ # ── TOML 行级 append(注释零破坏,不触碰已有内容)─────────────────────────
218
+
219
+ def _toml_escape(s: str) -> str:
220
+ """TOML 基本字符串转义(仅用于值;本实现值均为简单 ASCII/URL)。"""
221
+ return s.replace("\\", "\\\\").replace('"', '\\"')
222
+
223
+
224
+ def _toml_block(client: dict[str, Any], entry: dict[str, Any]) -> str:
225
+ """生成 [mcp_servers.argo] block 文本。"""
226
+ servers_key = client["servers_key"]
227
+ lines = [f"[{servers_key}.{ENTRY_NAME}]", f'command = "{_toml_escape(entry["command"])}"']
228
+ args = entry.get("args") or []
229
+ args_repr = ", ".join(f'"{_toml_escape(a)}"' for a in args)
230
+ lines.append(f"args = [{args_repr}]")
231
+ env = entry.get("env") or {}
232
+ if env:
233
+ # TOML 同键重复定义非法:此前每个键各写一行 `env = {...}`,一个键时
234
+ # 侥幸合法,第二个键起整份配置解析失败(潜伏雷,2026-10-02 锁定)。
235
+ # 全部键合并进一个内联表。
236
+ pairs = ", ".join(f'{k} = "{_toml_escape(v)}"' for k, v in env.items())
237
+ lines.append(f"env = {{ {pairs} }}")
238
+ return "\n".join(lines)
239
+
240
+
241
+ def _inject_toml(client: dict[str, Any], entry: dict[str, Any]) -> str:
242
+ """TOML 客户端注入:行级 append section。已存在则报错(不覆盖,避免破坏)。"""
243
+ path = _resolve(_client_config_path(client))
244
+ existing = path.read_text(encoding="utf-8") if path.exists() else ""
245
+ servers_key = client["servers_key"]
246
+ marker = f"[{servers_key}.{ENTRY_NAME}]"
247
+ if marker in existing:
248
+ raise ValueError(f"TOML 已含 argo 配置(若需更新请先 undo): {path}")
249
+ block = _toml_block(client, entry)
250
+ if existing and not existing.endswith("\n"):
251
+ existing += "\n\n"
252
+ elif existing:
253
+ existing += "\n"
254
+ return existing + block + "\n"
255
+
256
+
257
+ def _remove_toml(client: dict[str, Any]) -> str | None:
258
+ """TOML 客户端移除:删除 [mcp_servers.argo] section。"""
259
+ path = _resolve(_client_config_path(client))
260
+ if not path.exists():
261
+ return None
262
+ text = path.read_text(encoding="utf-8")
263
+ servers_key = client["servers_key"]
264
+ marker = f"[{servers_key}.{ENTRY_NAME}]"
265
+ if marker not in text:
266
+ return None
267
+ # 仅删该 section 到下一个 [section] 或文件尾
268
+ lines = text.splitlines(keepends=True)
269
+ out: list[str] = []
270
+ i = 0
271
+ in_target = False
272
+ while i < len(lines):
273
+ line = lines[i]
274
+ stripped = line.strip()
275
+ if stripped.startswith("[") and stripped.endswith("]"):
276
+ in_target = stripped == marker
277
+ if not in_target:
278
+ out.append(line)
279
+ i += 1
280
+ result = "".join(out).rstrip("\n") + "\n"
281
+ return result
282
+
283
+
284
+ # ── 诊断 ────────────────────────────────────────────────────────────────
285
+
286
+ def _entry_present(client: dict[str, Any]) -> bool:
287
+ path = _resolve(_client_config_path(client))
288
+ if not path.exists():
289
+ return False
290
+ fmt = client.get("format", "json")
291
+ if fmt == "toml":
292
+ return f"[{client['servers_key']}.{ENTRY_NAME}]" in path.read_text(encoding="utf-8")
293
+ try:
294
+ config = _json_read(path)
295
+ except ValueError:
296
+ return False
297
+ servers = config.get(client["servers_key"])
298
+ return isinstance(servers, dict) and ENTRY_NAME in servers
299
+
300
+
301
+ def _status_line(client: dict[str, Any]) -> str:
302
+ id_ = client["id"]
303
+ name = client["name"]
304
+ installed = detect(client)
305
+ configured = _entry_present(client)
306
+ # 标签自明(2026-10-02):光说「已安装」分不清装的是宿主应用还是
307
+ # argo 已注入——「已安装」恒指宿主存在而 argo 未注入
308
+ state = ("已配置(argo 已注入)" if configured
309
+ else "已安装(argo 未注入)" if installed
310
+ else "未安装")
311
+ return f" {id_:<12} {name:<14} {state}"
312
+
313
+
314
+ # ── 主命令 ──────────────────────────────────────────────────────────────
315
+
316
+ def cmd_status(clients: list[dict[str, Any]]) -> None:
317
+ print("Argo MCP 客户端状态\n")
318
+ for c in clients:
319
+ print(_status_line(c))
320
+ print("\n可用: inject [--all|--client ...] | undo [--all|--client ...] | status")
321
+
322
+
323
+ def _select(clients: list[dict[str, Any]], flags: list[str]) -> list[dict[str, Any]]:
324
+ """从 flags(--all 或 --client id 列表,支持逗号分隔)选目标客户端。
325
+
326
+ 返回已安装的目标;--all 选全部已安装。未知 id 忽略并提示。
327
+ """
328
+ if not flags:
329
+ return []
330
+ expanded: list[str] = []
331
+ for f in flags:
332
+ expanded.extend(x.strip() for x in f.split(",") if x.strip())
333
+ if any(x == "all" for x in expanded):
334
+ return [c for c in clients if detect(c)]
335
+ wanted = set(expanded)
336
+ unknown = wanted - {c["id"] for c in clients}
337
+ if unknown:
338
+ print(f" (忽略未知客户端: {', '.join(sorted(unknown))})")
339
+ return [c for c in clients if c["id"] in wanted]
340
+
341
+
342
+ def cmd_inject(clients: list[dict[str, Any]], flags: list[str], dry_run: bool) -> None:
343
+ targets = _select(clients, flags)
344
+ if not targets:
345
+ print("未找到匹配的已安装客户端。可执行 status 查看,或用 --all。")
346
+ return
347
+ print(f"将注入 {', '.join(c['name'] for c in targets)} ...\n")
348
+ for c in targets:
349
+ path = _resolve(_client_config_path(c))
350
+ fmt = c.get("format", "json")
351
+ entry = _mcp_command(c)
352
+ try:
353
+ if dry_run:
354
+ new_content = (
355
+ _inject_toml(c, entry) if fmt == "toml" else _inject_json(c, entry)
356
+ )
357
+ print(f" [dry-run] {c['name']} → {path}")
358
+ continue
359
+ backup = backup_file(path)
360
+ new_content = _inject_toml(c, entry) if fmt == "toml" else _inject_json(c, entry)
361
+ atomic_write(path, new_content, secret=True)
362
+ note = f"(备份 {backup.name})" if backup else ""
363
+ print(f" ✔ 已注入 {c['name']} → {path} {note}")
364
+ except (OSError, ValueError) as e:
365
+ print(f" ✘ {c['name']}: {e}")
366
+
367
+
368
+ def cmd_undo(clients: list[dict[str, Any]], flags: list[str], dry_run: bool) -> None:
369
+ targets = _select(clients, flags)
370
+ if not targets:
371
+ print("未找到匹配的客户端。可用 status 查看,或用 --all。")
372
+ return
373
+ print(f"将还原 {', '.join(c['name'] for c in targets)} ...\n")
374
+ for c in targets:
375
+ path = _resolve(_client_config_path(c))
376
+ fmt = c.get("format", "json")
377
+ try:
378
+ if dry_run:
379
+ print(f" [dry-run] {c['name']} → 移除 argo entry (或从备份回滚)")
380
+ continue
381
+ new_content = _remove_toml(c) if fmt == "toml" else _remove_json(c)
382
+ if new_content is None:
383
+ # entry 不存在 → 尝试从最近备份恢复
384
+ backups = list_backups(path.name)
385
+ if backups:
386
+ shutil.copy2(backups[0], path)
387
+ print(f" ↺ 从备份恢复 {c['name']} → {backups[0].name}")
388
+ else:
389
+ print(f" - {c['name']} 无 argo entry,无备份可恢复")
390
+ continue
391
+ atomic_write(path, new_content, secret=True)
392
+ print(f" ✔ 已还原 {c['name']} → {path}")
393
+ except (OSError, ValueError) as e:
394
+ print(f" ✘ {c['name']}: {e}")
395
+
396
+
397
+ def main(argv: list[str] | None = None) -> int:
398
+ parser = argparse.ArgumentParser(description="Argo 多客户端 MCP 注入/诊断/还原")
399
+ sub = parser.add_subparsers(dest="command", required=True)
400
+
401
+ p_status = sub.add_parser("status", help="诊断各客户端")
402
+
403
+ p_inject = sub.add_parser("inject", help="注入 MCP 配置")
404
+ p_inject.add_argument("--all", action="store_true", help="所有已安装客户端")
405
+ p_inject.add_argument("--client", action="append", default=[], help="指定客户端 id(可多次)")
406
+ p_inject.add_argument("--dry-run", action="store_true", help="只预览不写")
407
+
408
+ p_undo = sub.add_parser("undo", help="还原 MCP 配置")
409
+ p_undo.add_argument("--all", action="store_true", help="所有客户端")
410
+ p_undo.add_argument("--client", action="append", default=[], help="指定客户端 id(可多次)")
411
+ p_undo.add_argument("--dry-run", action="store_true", help="只预览不写")
412
+
413
+ args = parser.parse_args(argv)
414
+
415
+ try:
416
+ clients = load_clients()
417
+ except Exception as e:
418
+ print(f"加载客户端真源失败: {e}", file=sys.stderr)
419
+ return 1
420
+
421
+ if args.command == "status":
422
+ cmd_status(clients)
423
+ elif args.command == "inject":
424
+ cmd_inject(clients, (["all"] if args.all else args.client), args.dry_run)
425
+ elif args.command == "undo":
426
+ cmd_undo(clients, (["all"] if args.all else args.client), args.dry_run)
427
+ return 0
428
+
429
+
430
+ if __name__ == "__main__":
431
+ raise SystemExit(main())