@researai/deepscientist 1.5.17 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (894) hide show
  1. package/AGENTS.md +309 -130
  2. package/AISB/catalog/aisb.b1.agentic_coding.yaml +244 -0
  3. package/AISB/catalog/aisb.b10.climate_earth.yaml +235 -0
  4. package/AISB/catalog/aisb.b11.model_efficiency.yaml +231 -0
  5. package/AISB/catalog/aisb.b12.embodied_ai.yaml +238 -0
  6. package/AISB/catalog/aisb.b2.agent_systems.yaml +229 -0
  7. package/AISB/catalog/aisb.b3.self_evolving_rl.yaml +237 -0
  8. package/AISB/catalog/aisb.b4.lm_reasoning.yaml +240 -0
  9. package/AISB/catalog/aisb.b5.math_proof.yaml +235 -0
  10. package/AISB/catalog/aisb.b6.research_process.yaml +243 -0
  11. package/AISB/catalog/aisb.b7.multimodal_fusion.yaml +232 -0
  12. package/AISB/catalog/aisb.b8.lifesci_drug.yaml +275 -0
  13. package/AISB/catalog/aisb.b9.material_science.yaml +237 -0
  14. package/AISB/catalog/aisb.t3.001_savvy.yaml +159 -0
  15. package/AISB/catalog/aisb.t3.001_savvy.zh.yaml +121 -0
  16. package/AISB/catalog/aisb.t3.002_pinet.yaml +189 -0
  17. package/AISB/catalog/aisb.t3.002_pinet.zh.yaml +130 -0
  18. package/AISB/catalog/aisb.t3.004_decentralattn.yaml +184 -0
  19. package/AISB/catalog/aisb.t3.004_decentralattn.zh.yaml +153 -0
  20. package/AISB/catalog/aisb.t3.005_tsae.yaml +193 -0
  21. package/AISB/catalog/aisb.t3.005_tsae.zh.yaml +139 -0
  22. package/AISB/catalog/aisb.t3.006_physense.yaml +194 -0
  23. package/AISB/catalog/aisb.t3.006_physense.zh.yaml +118 -0
  24. package/AISB/catalog/aisb.t3.007_reasoningiqa.yaml +169 -0
  25. package/AISB/catalog/aisb.t3.007_reasoningiqa.zh.yaml +133 -0
  26. package/AISB/catalog/aisb.t3.008_meanflows.yaml +188 -0
  27. package/AISB/catalog/aisb.t3.008_meanflows.zh.yaml +140 -0
  28. package/AISB/catalog/aisb.t3.009_scoremissing.yaml +179 -0
  29. package/AISB/catalog/aisb.t3.009_scoremissing.zh.yaml +119 -0
  30. package/AISB/catalog/aisb.t3.010_suitabilityfilter.yaml +221 -0
  31. package/AISB/catalog/aisb.t3.010_suitabilityfilter.zh.yaml +141 -0
  32. package/AISB/catalog/aisb.t3.011_osd.yaml +206 -0
  33. package/AISB/catalog/aisb.t3.011_osd.zh.yaml +163 -0
  34. package/AISB/catalog/aisb.t3.012_efficientqat.yaml +206 -0
  35. package/AISB/catalog/aisb.t3.012_efficientqat.zh.yaml +159 -0
  36. package/AISB/catalog/aisb.t3.013_appl.yaml +152 -0
  37. package/AISB/catalog/aisb.t3.013_appl.zh.yaml +126 -0
  38. package/AISB/catalog/aisb.t3.014_piguard.yaml +207 -0
  39. package/AISB/catalog/aisb.t3.014_piguard.zh.yaml +164 -0
  40. package/AISB/catalog/aisb.t3.015_frspec.yaml +209 -0
  41. package/AISB/catalog/aisb.t3.015_frspec.zh.yaml +163 -0
  42. package/AISB/catalog/aisb.t3.016_mathfusion.yaml +166 -0
  43. package/AISB/catalog/aisb.t3.016_mathfusion.zh.yaml +145 -0
  44. package/AISB/catalog/aisb.t3.017_multimodalglp.yaml +171 -0
  45. package/AISB/catalog/aisb.t3.017_multimodalglp.zh.yaml +122 -0
  46. package/AISB/catalog/aisb.t3.018_cotsynth.yaml +206 -0
  47. package/AISB/catalog/aisb.t3.018_cotsynth.zh.yaml +162 -0
  48. package/AISB/catalog/aisb.t3.019_dyscaleut.yaml +211 -0
  49. package/AISB/catalog/aisb.t3.019_dyscaleut.zh.yaml +148 -0
  50. package/AISB/catalog/aisb.t3.020_aristotle.yaml +173 -0
  51. package/AISB/catalog/aisb.t3.020_aristotle.zh.yaml +119 -0
  52. package/AISB/catalog/aisb.t3.021_tokenrecycling.yaml +160 -0
  53. package/AISB/catalog/aisb.t3.021_tokenrecycling.zh.yaml +129 -0
  54. package/AISB/catalog/aisb.t3.022_chainofreasoning.yaml +204 -0
  55. package/AISB/catalog/aisb.t3.022_chainofreasoning.zh.yaml +161 -0
  56. package/AISB/catalog/aisb.t3.023_guidedembed.yaml +211 -0
  57. package/AISB/catalog/aisb.t3.023_guidedembed.zh.yaml +189 -0
  58. package/AISB/catalog/aisb.t3.024_outputcentric.yaml +148 -0
  59. package/AISB/catalog/aisb.t3.024_outputcentric.zh.yaml +131 -0
  60. package/AISB/catalog/aisb.t3.025_deeper.yaml +143 -0
  61. package/AISB/catalog/aisb.t3.025_deeper.zh.yaml +116 -0
  62. package/AISB/catalog/aisb.t3.026_gartkg.yaml +195 -0
  63. package/AISB/catalog/aisb.t3.026_gartkg.zh.yaml +127 -0
  64. package/AISB/catalog/aisb.t3.027_citeeval.yaml +182 -0
  65. package/AISB/catalog/aisb.t3.027_citeeval.zh.yaml +135 -0
  66. package/AISB/catalog/aisb.t3.028_sbam.yaml +206 -0
  67. package/AISB/catalog/aisb.t3.028_sbam.zh.yaml +166 -0
  68. package/AISB/catalog/aisb.t3.029_cdqgeoembed.yaml +224 -0
  69. package/AISB/catalog/aisb.t3.029_cdqgeoembed.zh.yaml +142 -0
  70. package/AISB/catalog/aisb.t3.030_processrm.yaml +211 -0
  71. package/AISB/catalog/aisb.t3.030_processrm.zh.yaml +166 -0
  72. package/AISB/catalog/aisb.t3.031_circuitstability.yaml +172 -0
  73. package/AISB/catalog/aisb.t3.031_circuitstability.zh.yaml +134 -0
  74. package/AISB/catalog/aisb.t3.032_ptsolver.yaml +169 -0
  75. package/AISB/catalog/aisb.t3.032_ptsolver.zh.yaml +135 -0
  76. package/AISB/catalog/aisb.t3.033_gcse.yaml +144 -0
  77. package/AISB/catalog/aisb.t3.033_gcse.zh.yaml +126 -0
  78. package/AISB/catalog/aisb.t3.034_ensemblewm.yaml +183 -0
  79. package/AISB/catalog/aisb.t3.034_ensemblewm.zh.yaml +146 -0
  80. package/AISB/catalog/aisb.t3.035_moralvalueswa.yaml +207 -0
  81. package/AISB/catalog/aisb.t3.035_moralvalueswa.zh.yaml +165 -0
  82. package/AISB/catalog/aisb.t3.036_weakstrongpref.yaml +210 -0
  83. package/AISB/catalog/aisb.t3.036_weakstrongpref.zh.yaml +194 -0
  84. package/AISB/catalog/aisb.t3.037_dementiamask.yaml +172 -0
  85. package/AISB/catalog/aisb.t3.037_dementiamask.zh.yaml +132 -0
  86. package/AISB/catalog/aisb.t3.038_tinysam.yaml +284 -0
  87. package/AISB/catalog/aisb.t3.038_tinysam.zh.yaml +240 -0
  88. package/AISB/catalog/aisb.t3.039_calf.yaml +224 -0
  89. package/AISB/catalog/aisb.t3.039_calf.zh.yaml +194 -0
  90. package/AISB/catalog/aisb.t3.040_graniteguardian.yaml +199 -0
  91. package/AISB/catalog/aisb.t3.040_graniteguardian.zh.yaml +174 -0
  92. package/AISB/catalog/aisb.t3.041_amdm.yaml +149 -0
  93. package/AISB/catalog/aisb.t3.041_amdm.zh.yaml +137 -0
  94. package/AISB/catalog/aisb.t3.042_xpatch.yaml +216 -0
  95. package/AISB/catalog/aisb.t3.042_xpatch.zh.yaml +182 -0
  96. package/AISB/catalog/aisb.t3.043_vhm.yaml +268 -0
  97. package/AISB/catalog/aisb.t3.043_vhm.zh.yaml +193 -0
  98. package/AISB/catalog/aisb.t3.044_rgvi.yaml +224 -0
  99. package/AISB/catalog/aisb.t3.044_rgvi.zh.yaml +176 -0
  100. package/AISB/catalog/aisb.t3.045_pslstm.yaml +203 -0
  101. package/AISB/catalog/aisb.t3.045_pslstm.zh.yaml +179 -0
  102. package/AISB/catalog/aisb.t3.046_nonstatts.yaml +208 -0
  103. package/AISB/catalog/aisb.t3.046_nonstatts.zh.yaml +194 -0
  104. package/AISB/catalog/aisb.t3.047_timepfn.yaml +156 -0
  105. package/AISB/catalog/aisb.t3.047_timepfn.zh.yaml +124 -0
  106. package/AISB/catalog/aisb.t3.048_proxyspex.yaml +148 -0
  107. package/AISB/catalog/aisb.t3.048_proxyspex.zh.yaml +125 -0
  108. package/AISB/catalog/aisb.t3.049_hogwildinference.yaml +183 -0
  109. package/AISB/catalog/aisb.t3.049_hogwildinference.zh.yaml +138 -0
  110. package/AISB/catalog/aisb.t3.050_causalpfn.yaml +214 -0
  111. package/AISB/catalog/aisb.t3.050_causalpfn.zh.yaml +190 -0
  112. package/AISB/catalog/aisb.t3.051_flashtp.yaml +169 -0
  113. package/AISB/catalog/aisb.t3.051_flashtp.zh.yaml +124 -0
  114. package/AISB/catalog/aisb.t3.052_nsdiff.yaml +155 -0
  115. package/AISB/catalog/aisb.t3.052_nsdiff.zh.yaml +138 -0
  116. package/AISB/catalog/aisb.t3.053_k2vae.yaml +158 -0
  117. package/AISB/catalog/aisb.t3.053_k2vae.zh.yaml +132 -0
  118. package/AISB/catalog/aisb.t3.054_timebase.yaml +178 -0
  119. package/AISB/catalog/aisb.t3.054_timebase.zh.yaml +158 -0
  120. package/AISB/catalog/aisb.t3.055_csbrain.yaml +238 -0
  121. package/AISB/catalog/aisb.t3.055_csbrain.zh.yaml +184 -0
  122. package/AISB/catalog/aisb.t3.056_infosam.yaml +224 -0
  123. package/AISB/catalog/aisb.t3.056_infosam.zh.yaml +189 -0
  124. package/AISB/catalog/aisb.t3.057_mdreid.yaml +129 -0
  125. package/AISB/catalog/aisb.t3.057_mdreid.zh.yaml +117 -0
  126. package/AISB/catalog/aisb.t3.058_mindglitch.yaml +171 -0
  127. package/AISB/catalog/aisb.t3.058_mindglitch.zh.yaml +145 -0
  128. package/AISB/catalog/aisb.t3.059_selfsupervised.yaml +154 -0
  129. package/AISB/catalog/aisb.t3.059_selfsupervised.zh.yaml +125 -0
  130. package/AISB/catalog/aisb.t3.060_iaggad.yaml +121 -0
  131. package/AISB/catalog/aisb.t3.060_iaggad.zh.yaml +100 -0
  132. package/AISB/catalog/aisb.t3.061_hsgkn.yaml +136 -0
  133. package/AISB/catalog/aisb.t3.061_hsgkn.zh.yaml +113 -0
  134. package/AISB/catalog/aisb.t3.062_visionts.yaml +237 -0
  135. package/AISB/catalog/aisb.t3.062_visionts.zh.yaml +216 -0
  136. package/AISB/catalog/aisb.t3.063_tsrag.yaml +162 -0
  137. package/AISB/catalog/aisb.t3.063_tsrag.zh.yaml +138 -0
  138. package/AISB/catalog/aisb.t3.064_pir.yaml +221 -0
  139. package/AISB/catalog/aisb.t3.064_pir.zh.yaml +197 -0
  140. package/AISB/catalog/aisb.t3.065_proteinbinding.yaml +234 -0
  141. package/AISB/catalog/aisb.t3.065_proteinbinding.zh.yaml +167 -0
  142. package/AISB/catalog/aisb.t3.066_tropicalattention.yaml +267 -0
  143. package/AISB/catalog/aisb.t3.066_tropicalattention.zh.yaml +229 -0
  144. package/AISB/catalog/aisb.t3.067_kanad.yaml +193 -0
  145. package/AISB/catalog/aisb.t3.067_kanad.zh.yaml +167 -0
  146. package/AISB/catalog/aisb.t3.068_sempo.yaml +187 -0
  147. package/AISB/catalog/aisb.t3.068_sempo.zh.yaml +148 -0
  148. package/AISB/catalog/aisb.t3.069_treehfd.yaml +129 -0
  149. package/AISB/catalog/aisb.t3.069_treehfd.zh.yaml +111 -0
  150. package/AISB/catalog/aisb.t3.070_certifiedunlearning.yaml +224 -0
  151. package/AISB/catalog/aisb.t3.070_certifiedunlearning.zh.yaml +171 -0
  152. package/AISB/catalog/aisb.t3.071_neuralmjd.yaml +142 -0
  153. package/AISB/catalog/aisb.t3.071_neuralmjd.zh.yaml +120 -0
  154. package/AISB/catalog/aisb.t3.072_fedgmt.yaml +181 -0
  155. package/AISB/catalog/aisb.t3.072_fedgmt.zh.yaml +158 -0
  156. package/AISB/catalog/aisb.t3.073_rld.yaml +161 -0
  157. package/AISB/catalog/aisb.t3.073_rld.zh.yaml +129 -0
  158. package/AISB/catalog/aisb.t3.074_lsvi.yaml +163 -0
  159. package/AISB/catalog/aisb.t3.074_lsvi.zh.yaml +129 -0
  160. package/AISB/catalog/aisb.t3.075_treeslicedentropy.yaml +201 -0
  161. package/AISB/catalog/aisb.t3.075_treeslicedentropy.zh.yaml +148 -0
  162. package/AISB/catalog/aisb.t3.076_aanet.yaml +169 -0
  163. package/AISB/catalog/aisb.t3.076_aanet.zh.yaml +129 -0
  164. package/AISB/catalog/aisb.t3.077_cmnn.yaml +199 -0
  165. package/AISB/catalog/aisb.t3.077_cmnn.zh.yaml +165 -0
  166. package/AISB/catalog/aisb.t3.078_conformalanomaly.yaml +146 -0
  167. package/AISB/catalog/aisb.t3.078_conformalanomaly.zh.yaml +117 -0
  168. package/AISB/catalog/aisb.t3.079_dpfkmeans.yaml +131 -0
  169. package/AISB/catalog/aisb.t3.079_dpfkmeans.zh.yaml +104 -0
  170. package/AISB/catalog/aisb.t3.080_latentscorereweight.yaml +169 -0
  171. package/AISB/catalog/aisb.t3.080_latentscorereweight.zh.yaml +123 -0
  172. package/AISB/catalog/aisb.t3.081_qmamba.yaml +150 -0
  173. package/AISB/catalog/aisb.t3.081_qmamba.zh.yaml +117 -0
  174. package/AISB/catalog/aisb.t3.082_onlinellmrouting.yaml +160 -0
  175. package/AISB/catalog/aisb.t3.082_onlinellmrouting.zh.yaml +133 -0
  176. package/AISB/catalog/aisb.t3.083_starformer.yaml +178 -0
  177. package/AISB/catalog/aisb.t3.083_starformer.zh.yaml +140 -0
  178. package/AISB/catalog/aisb.t3.084_ift.yaml +139 -0
  179. package/AISB/catalog/aisb.t3.084_ift.zh.yaml +111 -0
  180. package/AISB/catalog/aisb.t3.085_neuralsurv.yaml +183 -0
  181. package/AISB/catalog/aisb.t3.085_neuralsurv.zh.yaml +143 -0
  182. package/AISB/catalog/aisb.t3.086_stella.yaml +197 -0
  183. package/AISB/catalog/aisb.t3.086_stella.zh.yaml +142 -0
  184. package/AISB/catalog/aisb.t3.087_moses.yaml +167 -0
  185. package/AISB/catalog/aisb.t3.087_moses.zh.yaml +132 -0
  186. package/AISB/catalog/aisb.t3.088_channelnorm.yaml +140 -0
  187. package/AISB/catalog/aisb.t3.088_channelnorm.zh.yaml +109 -0
  188. package/AISB/catalog/aisb.t3.089_causalvelocity.yaml +730 -0
  189. package/AISB/catalog/aisb.t3.089_causalvelocity.zh.yaml +668 -0
  190. package/AISB/catalog/aisb.t3.090_rstib.yaml +144 -0
  191. package/AISB/catalog/aisb.t3.090_rstib.zh.yaml +109 -0
  192. package/AISB/catalog/aisb.t3.091_timeawarecausal.yaml +132 -0
  193. package/AISB/catalog/aisb.t3.091_timeawarecausal.zh.yaml +107 -0
  194. package/AISB/catalog/aisb.t3.092_kmeanslocalopt.yaml +138 -0
  195. package/AISB/catalog/aisb.t3.092_kmeanslocalopt.zh.yaml +110 -0
  196. package/AISB/catalog/aisb.t3.093_fedwmsam.yaml +134 -0
  197. package/AISB/catalog/aisb.t3.093_fedwmsam.zh.yaml +106 -0
  198. package/AISB/catalog/aisb.t3.094_boundre.yaml +147 -0
  199. package/AISB/catalog/aisb.t3.094_boundre.zh.yaml +114 -0
  200. package/AISB/catalog/aisb.t3.095_fastfeaturecp.yaml +153 -0
  201. package/AISB/catalog/aisb.t3.095_fastfeaturecp.zh.yaml +118 -0
  202. package/AISB/catalog/aisb.t3.096_m3svm.yaml +189 -0
  203. package/AISB/catalog/aisb.t3.096_m3svm.zh.yaml +149 -0
  204. package/AISB/catalog/aisb.t3.097_wassersteintl.yaml +212 -0
  205. package/AISB/catalog/aisb.t3.097_wassersteintl.zh.yaml +169 -0
  206. package/AISB/catalog/aisb.t3.098_xmahalanobis.yaml +171 -0
  207. package/AISB/catalog/aisb.t3.098_xmahalanobis.zh.yaml +127 -0
  208. package/AISB/catalog/aisb.t3.099_ollalanding.yaml +248 -0
  209. package/AISB/catalog/aisb.t3.099_ollalanding.zh.yaml +182 -0
  210. package/AISB/catalog/aisb.t3.100_invmissingdata.yaml +179 -0
  211. package/AISB/catalog/aisb.t3.100_invmissingdata.zh.yaml +150 -0
  212. package/AISB/catalog/aisb.t3.101_acia.yaml +164 -0
  213. package/AISB/catalog/aisb.t3.101_acia.zh.yaml +109 -0
  214. package/AISB/catalog/aisb.t3.102_stochasticff.yaml +178 -0
  215. package/AISB/catalog/aisb.t3.102_stochasticff.zh.yaml +130 -0
  216. package/AISB/catalog/aisb.t3.103_qdcp.yaml +150 -0
  217. package/AISB/catalog/aisb.t3.103_qdcp.zh.yaml +116 -0
  218. package/AISB/catalog/aisb.t3.104_balancedactiveinf.yaml +137 -0
  219. package/AISB/catalog/aisb.t3.104_balancedactiveinf.zh.yaml +104 -0
  220. package/AISB/catalog/aisb.t3.105_binaryclasseval.yaml +161 -0
  221. package/AISB/catalog/aisb.t3.105_binaryclasseval.zh.yaml +130 -0
  222. package/AISB/image/001_aisb.t3.001_savvy.jpg +0 -0
  223. package/AISB/image/002_aisb.t3.002_pinet.jpg +0 -0
  224. package/AISB/image/003_aisb.t3.003_dmsqd.jpg +0 -0
  225. package/AISB/image/004_aisb.t3.004_decentralattn.jpg +0 -0
  226. package/AISB/image/005_aisb.t3.005_tsae.jpg +0 -0
  227. package/AISB/image/006_aisb.t3.006_physense.jpg +0 -0
  228. package/AISB/image/007_aisb.t3.007_reasoningiqa.jpg +0 -0
  229. package/AISB/image/008_aisb.t3.008_meanflows.jpg +0 -0
  230. package/AISB/image/009_aisb.t3.009_scoremissing.jpg +0 -0
  231. package/AISB/image/010_aisb.t3.010_suitabilityfilter.jpg +0 -0
  232. package/AISB/image/011_aisb.t3.011_osd.jpg +0 -0
  233. package/AISB/image/012_aisb.t3.012_efficientqat.jpg +0 -0
  234. package/AISB/image/013_aisb.t3.013_appl.jpg +0 -0
  235. package/AISB/image/014_aisb.t3.014_piguard.jpg +0 -0
  236. package/AISB/image/015_aisb.t3.015_frspec.jpg +0 -0
  237. package/AISB/image/016_aisb.t3.016_mathfusion.jpg +0 -0
  238. package/AISB/image/017_aisb.t3.017_multimodalglp.jpg +0 -0
  239. package/AISB/image/018_aisb.t3.018_cotsynth.jpg +0 -0
  240. package/AISB/image/019_aisb.t3.019_dyscaleut.jpg +0 -0
  241. package/AISB/image/020_aisb.t3.020_aristotle.jpg +0 -0
  242. package/AISB/image/021_aisb.t3.021_tokenrecycling.jpg +0 -0
  243. package/AISB/image/022_aisb.t3.022_chainofreasoning.jpg +0 -0
  244. package/AISB/image/023_aisb.t3.023_guidedembed.jpg +0 -0
  245. package/AISB/image/024_aisb.t3.024_outputcentric.jpg +0 -0
  246. package/AISB/image/025_aisb.t3.025_deeper.jpg +0 -0
  247. package/AISB/image/026_aisb.t3.026_gartkg.jpg +0 -0
  248. package/AISB/image/027_aisb.t3.027_citeeval.jpg +0 -0
  249. package/AISB/image/028_aisb.t3.028_sbam.jpg +0 -0
  250. package/AISB/image/029_aisb.t3.029_cdqgeoembed.jpg +0 -0
  251. package/AISB/image/030_aisb.t3.030_processrm.jpg +0 -0
  252. package/AISB/image/031_aisb.t3.031_circuitstability.jpg +0 -0
  253. package/AISB/image/032_aisb.t3.032_ptsolver.jpg +0 -0
  254. package/AISB/image/033_aisb.t3.033_gcse.jpg +0 -0
  255. package/AISB/image/034_aisb.t3.034_ensemblewm.jpg +0 -0
  256. package/AISB/image/035_aisb.t3.035_moralvalueswa.jpg +0 -0
  257. package/AISB/image/036_aisb.t3.036_weakstrongpref.jpg +0 -0
  258. package/AISB/image/037_aisb.t3.037_dementiamask.jpg +0 -0
  259. package/AISB/image/038_aisb.t3.038_tinysam.jpg +0 -0
  260. package/AISB/image/039_aisb.t3.039_calf.jpg +0 -0
  261. package/AISB/image/040_aisb.t3.040_graniteguardian.jpg +0 -0
  262. package/AISB/image/041_aisb.t3.041_amdm.jpg +0 -0
  263. package/AISB/image/042_aisb.t3.042_xpatch.jpg +0 -0
  264. package/AISB/image/043_aisb.t3.043_vhm.jpg +0 -0
  265. package/AISB/image/044_aisb.t3.044_rgvi.jpg +0 -0
  266. package/AISB/image/045_aisb.t3.045_pslstm.jpg +0 -0
  267. package/AISB/image/046_aisb.t3.046_nonstatts.jpg +0 -0
  268. package/AISB/image/047_aisb.t3.047_timepfn.jpg +0 -0
  269. package/AISB/image/048_aisb.t3.048_proxyspex.jpg +0 -0
  270. package/AISB/image/049_aisb.t3.049_hogwildinference.jpg +0 -0
  271. package/AISB/image/050_aisb.t3.050_causalpfn.jpg +0 -0
  272. package/AISB/image/051_aisb.t3.051_flashtp.jpg +0 -0
  273. package/AISB/image/052_aisb.t3.052_nsdiff.jpg +0 -0
  274. package/AISB/image/053_aisb.t3.053_k2vae.jpg +0 -0
  275. package/AISB/image/054_aisb.t3.054_timebase.jpg +0 -0
  276. package/AISB/image/055_aisb.t3.055_csbrain.jpg +0 -0
  277. package/AISB/image/056_aisb.t3.056_infosam.jpg +0 -0
  278. package/AISB/image/057_aisb.t3.057_mdreid.jpg +0 -0
  279. package/AISB/image/058_aisb.t3.058_mindglitch.jpg +0 -0
  280. package/AISB/image/059_aisb.t3.059_selfsupervised.jpg +0 -0
  281. package/AISB/image/060_aisb.t3.060_iaggad.jpg +0 -0
  282. package/AISB/image/061_aisb.t3.061_hsgkn.jpg +0 -0
  283. package/AISB/image/062_aisb.t3.062_visionts.jpg +0 -0
  284. package/AISB/image/063_aisb.t3.063_tsrag.jpg +0 -0
  285. package/AISB/image/064_aisb.t3.064_pir.jpg +0 -0
  286. package/AISB/image/065_aisb.t3.065_proteinbinding.jpg +0 -0
  287. package/AISB/image/066_aisb.t3.066_tropicalattention.jpg +0 -0
  288. package/AISB/image/067_aisb.t3.067_kanad.jpg +0 -0
  289. package/AISB/image/068_aisb.t3.068_sempo.jpg +0 -0
  290. package/AISB/image/069_aisb.t3.069_treehfd.jpg +0 -0
  291. package/AISB/image/070_aisb.t3.070_certifiedunlearning.jpg +0 -0
  292. package/AISB/image/071_aisb.t3.071_neuralmjd.jpg +0 -0
  293. package/AISB/image/072_aisb.t3.072_fedgmt.jpg +0 -0
  294. package/AISB/image/073_aisb.t3.073_rld.jpg +0 -0
  295. package/AISB/image/074_aisb.t3.074_lsvi.jpg +0 -0
  296. package/AISB/image/075_aisb.t3.075_treeslicedentropy.jpg +0 -0
  297. package/AISB/image/076_aisb.t3.076_aanet.jpg +0 -0
  298. package/AISB/image/077_aisb.t3.077_cmnn.jpg +0 -0
  299. package/AISB/image/078_aisb.t3.078_conformalanomaly.jpg +0 -0
  300. package/AISB/image/079_aisb.t3.079_dpfkmeans.jpg +0 -0
  301. package/AISB/image/080_aisb.t3.080_latentscorereweight.jpg +0 -0
  302. package/AISB/image/081_aisb.t3.081_qmamba.jpg +0 -0
  303. package/AISB/image/082_aisb.t3.082_onlinellmrouting.jpg +0 -0
  304. package/AISB/image/083_aisb.t3.083_starformer.jpg +0 -0
  305. package/AISB/image/084_aisb.t3.084_ift.jpg +0 -0
  306. package/AISB/image/085_aisb.t3.085_neuralsurv.jpg +0 -0
  307. package/AISB/image/086_aisb.t3.086_stella.jpg +0 -0
  308. package/AISB/image/087_aisb.t3.087_moses.jpg +0 -0
  309. package/AISB/image/088_aisb.t3.088_channelnorm.jpg +0 -0
  310. package/AISB/image/089_aisb.t3.089_causalvelocity.jpg +0 -0
  311. package/AISB/image/090_aisb.t3.090_rstib.jpg +0 -0
  312. package/AISB/image/091_aisb.t3.091_timeawarecausal.jpg +0 -0
  313. package/AISB/image/092_aisb.t3.092_kmeanslocalopt.jpg +0 -0
  314. package/AISB/image/093_aisb.t3.093_fedwmsam.jpg +0 -0
  315. package/AISB/image/094_aisb.t3.094_boundre.jpg +0 -0
  316. package/AISB/image/095_aisb.t3.095_fastfeaturecp.jpg +0 -0
  317. package/AISB/image/096_aisb.t3.096_m3svm.jpg +0 -0
  318. package/AISB/image/097_aisb.t3.097_wassersteintl.jpg +0 -0
  319. package/AISB/image/098_aisb.t3.098_xmahalanobis.jpg +0 -0
  320. package/AISB/image/099_aisb.t3.099_ollalanding.jpg +0 -0
  321. package/AISB/image/100_aisb.t3.100_invmissingdata.jpg +0 -0
  322. package/AISB/image/101_aisb.t3.101_acia.jpg +0 -0
  323. package/AISB/image/102_aisb.t3.102_stochasticff.jpg +0 -0
  324. package/AISB/image/103_aisb.t3.103_qdcp.jpg +0 -0
  325. package/AISB/image/104_aisb.t3.104_balancedactiveinf.jpg +0 -0
  326. package/AISB/image/105_aisb.t3.105_binaryclasseval.jpg +0 -0
  327. package/AISB/image/106_aisb.t1.reasoning_lite.jpg +0 -0
  328. package/AISB/image/107_aisb.t2.paper_audit.jpg +0 -0
  329. package/AISB/image/108_aisb.t3.multi_gpu_search.jpg +0 -0
  330. package/AISB/image/109_aisb.t3.tdc_admet.jpg +0 -0
  331. package/AISB/image/aisb.b1.agentic_coding.svg +16 -0
  332. package/AISB/image/aisb.b10.climate_earth.svg +16 -0
  333. package/AISB/image/aisb.b11.model_efficiency.svg +16 -0
  334. package/AISB/image/aisb.b12.embodied_ai.svg +16 -0
  335. package/AISB/image/aisb.b2.agent_systems.svg +16 -0
  336. package/AISB/image/aisb.b3.self_evolving_rl.svg +16 -0
  337. package/AISB/image/aisb.b4.lm_reasoning.svg +16 -0
  338. package/AISB/image/aisb.b5.math_proof.svg +16 -0
  339. package/AISB/image/aisb.b6.research_process.svg +16 -0
  340. package/AISB/image/aisb.b7.multimodal_fusion.svg +16 -0
  341. package/AISB/image/aisb.b8.lifesci_drug.svg +16 -0
  342. package/AISB/image/aisb.b9.material_science.svg +16 -0
  343. package/README.md +132 -11
  344. package/bin/ds.js +376 -49
  345. package/docs/en/00_QUICK_START.md +135 -18
  346. package/docs/en/01_SETTINGS_REFERENCE.md +468 -96
  347. package/docs/en/02_START_RESEARCH_GUIDE.md +26 -5
  348. package/docs/en/03_QQ_CONNECTOR_GUIDE.md +14 -3
  349. package/docs/en/04_LINGZHU_CONNECTOR_GUIDE.md +2 -0
  350. package/docs/en/05_TUI_GUIDE.md +171 -2
  351. package/docs/en/07_MEMORY_AND_MCP.md +38 -2
  352. package/docs/en/09_DOCTOR.md +64 -4
  353. package/docs/en/10_WEIXIN_CONNECTOR_GUIDE.md +38 -1
  354. package/docs/en/11_LICENSE_AND_RISK.md +4 -0
  355. package/docs/en/12_GUIDED_WORKFLOW_TOUR.md +15 -0
  356. package/docs/en/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +9 -0
  357. package/docs/en/15_CODEX_PROVIDER_SETUP.md +622 -187
  358. package/docs/en/16_TELEGRAM_CONNECTOR_GUIDE.md +14 -0
  359. package/docs/en/17_WHATSAPP_CONNECTOR_GUIDE.md +14 -0
  360. package/docs/en/18_FEISHU_CONNECTOR_GUIDE.md +14 -0
  361. package/docs/en/21_LOCAL_MODEL_BACKENDS_GUIDE.md +105 -2
  362. package/docs/en/22_BENCHSTORE_YAML_REFERENCE.md +469 -0
  363. package/docs/en/23_BENCHSTORE_GITHUB_RELEASES_SPEC.md +316 -0
  364. package/docs/en/24_CLAUDE_CODE_PROVIDER_SETUP.md +469 -0
  365. package/docs/en/25_OPENCODE_PROVIDER_SETUP.md +653 -0
  366. package/docs/en/26_CITATION_AND_ATTRIBUTION.md +119 -0
  367. package/docs/en/27_KIMI_CODE_PROVIDER_SETUP.md +180 -0
  368. package/docs/en/28_DISCORD_CONNECTOR_GUIDE.md +61 -0
  369. package/docs/en/29_SLACK_CONNECTOR_GUIDE.md +60 -0
  370. package/docs/en/30_SETTINGS_CONTROL_CENTER_GUIDE.md +371 -0
  371. package/docs/en/{19_LOCAL_BROWSER_AUTH.md → 31_LOCAL_BROWSER_AUTH.md} +1 -1
  372. package/docs/en/32_WINDOWS_WSL2_DEPLOYMENT_GUIDE.md +273 -0
  373. package/docs/en/33_WORKSPACE_EXPLORER_QA.md +121 -0
  374. package/docs/en/91_DEVELOPMENT.md +29 -0
  375. package/docs/en/99_ACKNOWLEDGEMENTS.md +24 -19
  376. package/docs/en/README.md +44 -7
  377. package/docs/images/admin/admin-connectors-health-en.png +0 -0
  378. package/docs/images/admin/admin-controllers-en.png +0 -0
  379. package/docs/images/admin/admin-diagnostics-en.png +0 -0
  380. package/docs/images/admin/admin-errors-en.png +0 -0
  381. package/docs/images/admin/admin-issues-en.png +0 -0
  382. package/docs/images/admin/admin-logs-en.png +0 -0
  383. package/docs/images/admin/admin-quest-detail-en.png +0 -0
  384. package/docs/images/admin/admin-quests-en.png +0 -0
  385. package/docs/images/admin/admin-repairs-en.png +0 -0
  386. package/docs/images/admin/admin-runtime-en.png +0 -0
  387. package/docs/images/admin/admin-search-en.png +0 -0
  388. package/docs/images/admin/admin-stats-en.png +0 -0
  389. package/docs/images/admin/admin-summary-en.png +0 -0
  390. package/docs/images/connectors/connector-discord-en.png +0 -0
  391. package/docs/images/connectors/connector-feishu-en.png +0 -0
  392. package/docs/images/connectors/connector-lingzhu-en.png +0 -0
  393. package/docs/images/connectors/connector-qq-en.png +0 -0
  394. package/docs/images/connectors/connector-slack-en.png +0 -0
  395. package/docs/images/connectors/connector-telegram-en.png +0 -0
  396. package/docs/images/connectors/connector-weixin-en.png +0 -0
  397. package/docs/images/connectors/connector-whatsapp-en.png +0 -0
  398. package/docs/images/settings/settings-baselines-en.png +0 -0
  399. package/docs/images/settings/settings-config-en.png +0 -0
  400. package/docs/images/settings/settings-connectors-overview-en.png +0 -0
  401. package/docs/images/settings/settings-deepxiv-en.png +0 -0
  402. package/docs/images/settings/settings-mcp-servers-en.png +0 -0
  403. package/docs/images/settings/settings-plugins-en.png +0 -0
  404. package/docs/images/settings/settings-runners-en.png +0 -0
  405. package/docs/zh/00_QUICK_START.md +92 -17
  406. package/docs/zh/01_SETTINGS_REFERENCE.md +219 -98
  407. package/docs/zh/02_START_RESEARCH_GUIDE.md +26 -5
  408. package/docs/zh/05_TUI_GUIDE.md +171 -2
  409. package/docs/zh/07_MEMORY_AND_MCP.md +29 -2
  410. package/docs/zh/09_DOCTOR.md +39 -4
  411. package/docs/zh/10_WEIXIN_CONNECTOR_GUIDE.md +24 -1
  412. package/docs/zh/11_LICENSE_AND_RISK.md +4 -0
  413. package/docs/zh/12_GUIDED_WORKFLOW_TOUR.md +15 -0
  414. package/docs/zh/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +9 -0
  415. package/docs/zh/15_CODEX_PROVIDER_SETUP.md +550 -188
  416. package/docs/zh/21_LOCAL_MODEL_BACKENDS_GUIDE.md +105 -2
  417. package/docs/zh/22_BENCHSTORE_YAML_REFERENCE.md +459 -0
  418. package/docs/zh/23_BENCHSTORE_GITHUB_RELEASES_SPEC.md +287 -0
  419. package/docs/zh/23_CLAUDE_RUNNER_GUIDE.md +103 -0
  420. package/docs/zh/24_CLAUDE_CODE_PROVIDER_SETUP.md +460 -0
  421. package/docs/zh/25_OPENCODE_PROVIDER_SETUP.md +660 -0
  422. package/docs/zh/26_CITATION_AND_ATTRIBUTION.md +102 -0
  423. package/docs/zh/27_KIMI_CODE_PROVIDER_SETUP.md +51 -0
  424. package/docs/zh/{19_LOCAL_BROWSER_AUTH.md → 31_LOCAL_BROWSER_AUTH.md} +1 -1
  425. package/docs/zh/32_WINDOWS_WSL2_DEPLOYMENT_GUIDE.md +264 -0
  426. package/docs/zh/33_WORKSPACE_EXPLORER_QA.md +127 -0
  427. package/docs/zh/99_ACKNOWLEDGEMENTS.md +23 -19
  428. package/docs/zh/README.md +29 -7
  429. package/install.sh +122 -16
  430. package/package.json +4 -1
  431. package/pyproject.toml +2 -1
  432. package/src/deepscientist/__init__.py +1 -1
  433. package/src/deepscientist/acp/envelope.py +13 -0
  434. package/src/deepscientist/admin/__init__.py +3 -0
  435. package/src/deepscientist/admin/charts.py +681 -0
  436. package/src/deepscientist/admin/logs.py +119 -0
  437. package/src/deepscientist/admin/repairs.py +217 -0
  438. package/src/deepscientist/admin/service.py +1310 -0
  439. package/src/deepscientist/admin/system_info.py +700 -0
  440. package/src/deepscientist/admin/tasks.py +465 -0
  441. package/src/deepscientist/admin/tool_metrics.py +600 -0
  442. package/src/deepscientist/artifact/guidance.py +8 -4
  443. package/src/deepscientist/artifact/schemas.py +115 -0
  444. package/src/deepscientist/artifact/service.py +4268 -260
  445. package/src/deepscientist/bash_exec/monitor.py +30 -3
  446. package/src/deepscientist/bash_exec/service.py +134 -1
  447. package/src/deepscientist/benchstore/__init__.py +4 -0
  448. package/src/deepscientist/benchstore/prompt_builder.py +224 -0
  449. package/src/deepscientist/benchstore/service.py +1716 -0
  450. package/src/deepscientist/channels/weixin_ilink.py +8 -1
  451. package/src/deepscientist/cli.py +92 -17
  452. package/src/deepscientist/codex_cli_compat.py +2 -2
  453. package/src/deepscientist/config/models.py +82 -11
  454. package/src/deepscientist/config/service.py +927 -91
  455. package/src/deepscientist/connector/weixin_support.py +48 -17
  456. package/src/deepscientist/daemon/api/handlers.py +697 -210
  457. package/src/deepscientist/daemon/api/router.py +76 -1
  458. package/src/deepscientist/daemon/app.py +1054 -51
  459. package/src/deepscientist/diagnostics/runner_failures.py +147 -0
  460. package/src/deepscientist/doctor.py +212 -65
  461. package/src/deepscientist/evidence_packets.py +590 -0
  462. package/src/deepscientist/home.py +52 -4
  463. package/src/deepscientist/kimi_cli_compat.py +50 -0
  464. package/src/deepscientist/latex_runtime.py +2 -2
  465. package/src/deepscientist/mcp/context.py +2 -0
  466. package/src/deepscientist/mcp/schemas.py +114 -0
  467. package/src/deepscientist/mcp/server.py +1566 -126
  468. package/src/deepscientist/memory/service.py +203 -16
  469. package/src/deepscientist/process_control.py +8 -1
  470. package/src/deepscientist/prompts/builder.py +836 -92
  471. package/src/deepscientist/quest/__init__.py +2 -2
  472. package/src/deepscientist/quest/layout.py +12 -1
  473. package/src/deepscientist/quest/node_traces.py +10 -0
  474. package/src/deepscientist/quest/service.py +1430 -139
  475. package/src/deepscientist/quest/stage_views.py +1 -1
  476. package/src/deepscientist/runners/__init__.py +18 -0
  477. package/src/deepscientist/runners/base.py +89 -1
  478. package/src/deepscientist/runners/builtins.py +13 -1
  479. package/src/deepscientist/runners/claude.py +391 -0
  480. package/src/deepscientist/runners/codex.py +421 -21
  481. package/src/deepscientist/runners/codex_telemetry.py +127 -0
  482. package/src/deepscientist/runners/kimi.py +334 -0
  483. package/src/deepscientist/runners/metadata.py +68 -0
  484. package/src/deepscientist/runners/opencode.py +414 -0
  485. package/src/deepscientist/runners/runtime_overrides.py +100 -0
  486. package/src/deepscientist/runners/simple_cli.py +538 -0
  487. package/src/deepscientist/runtime_storage.py +303 -0
  488. package/src/deepscientist/shared.py +61 -16
  489. package/src/deepscientist/skills/installer.py +37 -0
  490. package/src/deepscientist/skills/registry.py +2 -0
  491. package/src/deepscientist/tinytex.py +2 -2
  492. package/src/deepscientist/tui.py +10 -3
  493. package/src/prompts/benchstore/system.md +77 -0
  494. package/src/prompts/connectors/qq.md +33 -2
  495. package/src/prompts/connectors/weixin.md +208 -23
  496. package/src/prompts/contracts/admin_ops.md +74 -0
  497. package/src/prompts/contracts/admin_ops_knowledge.md +138 -0
  498. package/src/prompts/contracts/shared_interaction.md +5 -11
  499. package/src/prompts/start_setup/system.md +422 -0
  500. package/src/prompts/system.md +409 -315
  501. package/src/prompts/system_copilot.md +88 -12
  502. package/src/skills/analysis-campaign/SKILL.md +239 -578
  503. package/src/skills/analysis-campaign/references/artifact-flow-examples.md +102 -0
  504. package/src/skills/analysis-campaign/references/boundary-cases.md +98 -0
  505. package/src/skills/analysis-campaign/references/campaign-checklist-template.md +39 -24
  506. package/src/skills/analysis-campaign/references/campaign-design.md +26 -10
  507. package/src/skills/analysis-campaign/references/campaign-plan-template.md +53 -54
  508. package/src/skills/analysis-campaign/references/operational-guidance.md +97 -0
  509. package/src/skills/analysis-campaign/references/writing-facing-slice-examples.md +10 -20
  510. package/src/skills/baseline/SKILL.md +183 -461
  511. package/src/skills/baseline/references/artifact-flow-examples.md +106 -0
  512. package/src/skills/baseline/references/artifact-payload-examples.md +1 -1
  513. package/src/skills/baseline/references/baseline-checklist-template.md +27 -35
  514. package/src/skills/baseline/references/baseline-plan-template.md +37 -76
  515. package/src/skills/baseline/references/boundary-cases.md +86 -0
  516. package/src/skills/baseline/references/codebase-audit-checklist.md +2 -6
  517. package/src/skills/baseline/references/comparability-contract.md +7 -12
  518. package/src/skills/baseline/references/operational-guidance.md +56 -0
  519. package/src/skills/baseline/references/route-selection.md +5 -25
  520. package/src/skills/decision/SKILL.md +113 -306
  521. package/src/skills/decision/references/checkpoint-memory-template.md +47 -0
  522. package/src/skills/decision/references/operational-guidance.md +94 -0
  523. package/src/skills/decision/references/research-route-criteria.md +7 -8
  524. package/src/skills/decision/references/strategic-decision-template.md +13 -26
  525. package/src/skills/experiment/SKILL.md +132 -670
  526. package/src/skills/experiment/references/execution-playbook.md +374 -0
  527. package/src/skills/experiment/references/main-experiment-checklist-template.md +26 -2
  528. package/src/skills/experiment/references/main-experiment-plan-template.md +28 -17
  529. package/src/skills/experiment/references/operational-guidance.md +108 -0
  530. package/src/skills/finalize/SKILL.md +62 -0
  531. package/src/skills/finalize/references/checkpoint-memory-template.md +49 -0
  532. package/src/skills/finalize/references/resume-packet-template.md +7 -0
  533. package/src/skills/idea/SKILL.md +228 -15
  534. package/src/skills/idea/references/controlled-brainstorming-playbook.md +78 -0
  535. package/src/skills/idea/references/current-board-packet-template.md +61 -0
  536. package/src/skills/idea/references/high-value-idea-sourcing.md +119 -0
  537. package/src/skills/idea/references/idea-generation-playbook.md +21 -0
  538. package/src/skills/idea/references/idea-thinking-flow.md +6 -0
  539. package/src/skills/idea/references/literature-survey-template.md +3 -0
  540. package/src/skills/idea/references/objective-contract-template.md +54 -0
  541. package/src/skills/idea/references/outline-seeding-example.md +56 -0
  542. package/src/skills/idea/references/pre-idea-draft-template.md +105 -0
  543. package/src/skills/idea/references/related-work-playbook.md +75 -2
  544. package/src/skills/idea/references/research-history-playbook.md +114 -0
  545. package/src/skills/idea/references/selection-gate.md +58 -6
  546. package/src/skills/intake-audit/SKILL.md +43 -2
  547. package/src/skills/intake-audit/references/state-audit-template.md +10 -0
  548. package/src/skills/nature-data/SKILL.md +128 -0
  549. package/src/skills/nature-data/UPSTREAM_LICENSE.txt +21 -0
  550. package/src/skills/nature-data/agents/openai.yaml +4 -0
  551. package/src/skills/nature-data/references/chinese-author-alignment.md +84 -0
  552. package/src/skills/nature-data/references/fair-metadata-checklist.md +105 -0
  553. package/src/skills/nature-data/references/policy-principles.md +103 -0
  554. package/src/skills/nature-data/references/repository-and-identifiers.md +96 -0
  555. package/src/skills/nature-data/references/source-basis.md +54 -0
  556. package/src/skills/nature-data/references/statement-patterns.md +153 -0
  557. package/src/skills/nature-figure/SKILL.md +197 -0
  558. package/src/skills/nature-figure/UPSTREAM_LICENSE.txt +21 -0
  559. package/src/skills/nature-figure/agents/openai.yaml +4 -0
  560. package/src/skills/nature-figure/evals/evals.json +37 -0
  561. package/src/skills/nature-figure/references/api.md +428 -0
  562. package/src/skills/nature-figure/references/backend-selection.md +100 -0
  563. package/src/skills/nature-figure/references/chart-types.md +281 -0
  564. package/src/skills/nature-figure/references/common-patterns.md +349 -0
  565. package/src/skills/nature-figure/references/design-theory.md +436 -0
  566. package/src/skills/nature-figure/references/figure-contract.md +93 -0
  567. package/src/skills/nature-figure/references/nature-2026-observations.md +112 -0
  568. package/src/skills/nature-figure/references/qa-contract.md +119 -0
  569. package/src/skills/nature-figure/references/r-template-index.md +66 -0
  570. package/src/skills/nature-figure/references/r-workflow.md +161 -0
  571. package/src/skills/nature-figure/references/tutorials.md +250 -0
  572. package/src/skills/nature-paper2ppt/SKILL.md +507 -0
  573. package/src/skills/nature-paper2ppt/UPSTREAM_LICENSE.txt +21 -0
  574. package/src/skills/nature-paper2ppt/agents/openai.yaml +4 -0
  575. package/src/skills/nature-polishing/SKILL.md +385 -0
  576. package/src/skills/nature-polishing/UPSTREAM_LICENSE.txt +21 -0
  577. package/src/skills/nature-polishing/agents/openai.yaml +4 -0
  578. package/src/skills/nature-polishing/references/phrasebank-playbook.md +162 -0
  579. package/src/skills/nature-polishing/references/section-moves.md +240 -0
  580. package/src/skills/nature-polishing/references/style-guardrails.md +94 -0
  581. package/src/skills/nature-polishing/references/writing-strategy.md +148 -0
  582. package/src/skills/optimize/SKILL.md +177 -1568
  583. package/src/skills/optimize/references/brief-shaping-playbook.md +95 -0
  584. package/src/skills/optimize/references/candidate-board-template.md +13 -0
  585. package/src/skills/optimize/references/candidate-ranking-template.md +51 -0
  586. package/src/skills/optimize/references/codegen-route-playbook.md +50 -0
  587. package/src/skills/optimize/references/debug-response-template.md +29 -0
  588. package/src/skills/optimize/references/frontier-review-template.md +32 -0
  589. package/src/skills/optimize/references/fusion-playbook.md +36 -0
  590. package/src/skills/optimize/references/method-brief-template.md +73 -0
  591. package/src/skills/optimize/references/operational-guidance.md +621 -0
  592. package/src/skills/optimize/references/optimization-memory-template.md +30 -0
  593. package/src/skills/optimize/references/optimize-checklist-template.md +18 -0
  594. package/src/skills/optimize/references/plateau-response-playbook.md +28 -0
  595. package/src/skills/optimize/references/prompt-patterns.md +49 -0
  596. package/src/skills/paper-outline/SKILL.md +227 -0
  597. package/src/skills/paper-outline/references/outline-patterns.md +87 -0
  598. package/src/skills/paper-plot/SKILL.md +79 -0
  599. package/src/skills/paper-plot/agents/openai.yaml +4 -0
  600. package/src/skills/paper-plot/references/bar_grouped_hatch.md +96 -0
  601. package/src/skills/paper-plot/references/bar_paired_delta.md +72 -0
  602. package/src/skills/paper-plot/references/line_confidence_band.md +75 -0
  603. package/src/skills/paper-plot/references/line_loss_with_inset.md +65 -0
  604. package/src/skills/paper-plot/references/line_training_curve.md +44 -0
  605. package/src/skills/paper-plot/references/radar_dual_series.md +59 -0
  606. package/src/skills/paper-plot/references/scatter_broken_axis.md +59 -0
  607. package/src/skills/paper-plot/references/scatter_tsne_cluster.md +72 -0
  608. package/src/skills/paper-plot/scripts/bar_memevolve.py +109 -0
  609. package/src/skills/paper-plot/scripts/bar_spice.py +166 -0
  610. package/src/skills/paper-plot/scripts/line_aime.py +94 -0
  611. package/src/skills/paper-plot/scripts/line_loss_inset.py +157 -0
  612. package/src/skills/paper-plot/scripts/line_selfdistill.py +168 -0
  613. package/src/skills/paper-plot/scripts/radar_dora.py +151 -0
  614. package/src/skills/paper-plot/scripts/scatter_break.py +169 -0
  615. package/src/skills/paper-plot/scripts/scatter_tsne.py +133 -0
  616. package/src/skills/rebuttal/SKILL.md +9 -0
  617. package/src/skills/references/tool-usage-by-stage.md +438 -0
  618. package/src/skills/review/SKILL.md +105 -7
  619. package/src/skills/science/PROVENANCE.md +44 -0
  620. package/src/skills/science/SKILL.md +137 -0
  621. package/src/skills/science/references/artifact-science-tool.md +110 -0
  622. package/src/skills/science/references/claim-type-discipline.md +56 -0
  623. package/src/skills/science/references/domain-index.md +422 -0
  624. package/src/skills/science/references/hpc-via-bash-exec.md +42 -0
  625. package/src/skills/science/references/package-check-playbook.md +64 -0
  626. package/src/skills/science/references/package-index.min.json +3616 -0
  627. package/src/skills/science/references/packages/abinit.md +80 -0
  628. package/src/skills/science/references/packages/acts.md +73 -0
  629. package/src/skills/science/references/packages/aiida-core.md +80 -0
  630. package/src/skills/science/references/packages/alamode.md +80 -0
  631. package/src/skills/science/references/packages/amuse.md +88 -0
  632. package/src/skills/science/references/packages/anndata.md +88 -0
  633. package/src/skills/science/references/packages/arbor.md +80 -0
  634. package/src/skills/science/references/packages/arc.md +73 -0
  635. package/src/skills/science/references/packages/astropy.md +88 -0
  636. package/src/skills/science/references/packages/astroquery.md +88 -0
  637. package/src/skills/science/references/packages/atomate2.md +80 -0
  638. package/src/skills/science/references/packages/atomsmltr.md +73 -0
  639. package/src/skills/science/references/packages/awkward.md +73 -0
  640. package/src/skills/science/references/packages/batman.md +88 -0
  641. package/src/skills/science/references/packages/biopython.md +88 -0
  642. package/src/skills/science/references/packages/bloqade.md +73 -0
  643. package/src/skills/science/references/packages/brian2.md +73 -0
  644. package/src/skills/science/references/packages/bullet3.md +73 -0
  645. package/src/skills/science/references/packages/calculix.md +80 -0
  646. package/src/skills/science/references/packages/cantera.md +73 -0
  647. package/src/skills/science/references/packages/cavity-md-ipi.md +80 -0
  648. package/src/skills/science/references/packages/ccdproc.md +88 -0
  649. package/src/skills/science/references/packages/celerite2.md +88 -0
  650. package/src/skills/science/references/packages/cellrank.md +73 -0
  651. package/src/skills/science/references/packages/cesm.md +80 -0
  652. package/src/skills/science/references/packages/chemicals.md +73 -0
  653. package/src/skills/science/references/packages/chempy.md +73 -0
  654. package/src/skills/science/references/packages/cirq.md +73 -0
  655. package/src/skills/science/references/packages/coffea.md +73 -0
  656. package/src/skills/science/references/packages/cp2k.md +88 -0
  657. package/src/skills/science/references/packages/custodian.md +80 -0
  658. package/src/skills/science/references/packages/dart.md +73 -0
  659. package/src/skills/science/references/packages/datamol.md +88 -0
  660. package/src/skills/science/references/packages/dd4hep.md +73 -0
  661. package/src/skills/science/references/packages/dealii.md +80 -0
  662. package/src/skills/science/references/packages/deepchem.md +88 -0
  663. package/src/skills/science/references/packages/delphes.md +73 -0
  664. package/src/skills/science/references/packages/devito.md +80 -0
  665. package/src/skills/science/references/packages/dftb.md +88 -0
  666. package/src/skills/science/references/packages/dftd4.md +88 -0
  667. package/src/skills/science/references/packages/dftk-jl.md +80 -0
  668. package/src/skills/science/references/packages/dolfinx.md +80 -0
  669. package/src/skills/science/references/packages/drake.md +73 -0
  670. package/src/skills/science/references/packages/dumux.md +73 -0
  671. package/src/skills/science/references/packages/elk.md +80 -0
  672. package/src/skills/science/references/packages/elmerfem.md +80 -0
  673. package/src/skills/science/references/packages/enzo-e.md +88 -0
  674. package/src/skills/science/references/packages/espresso.md +80 -0
  675. package/src/skills/science/references/packages/exoplanet.md +88 -0
  676. package/src/skills/science/references/packages/fairroot.md +73 -0
  677. package/src/skills/science/references/packages/fbpic.md +80 -0
  678. package/src/skills/science/references/packages/fdtdbath-meep.md +80 -0
  679. package/src/skills/science/references/packages/geant4.md +73 -0
  680. package/src/skills/science/references/packages/geosx.md +80 -0
  681. package/src/skills/science/references/packages/gprmax.md +80 -0
  682. package/src/skills/science/references/packages/gromacs.md +80 -0
  683. package/src/skills/science/references/packages/gwaslab.md +73 -0
  684. package/src/skills/science/references/packages/gz-sim.md +73 -0
  685. package/src/skills/science/references/packages/hail.md +88 -0
  686. package/src/skills/science/references/packages/hiphive.md +80 -0
  687. package/src/skills/science/references/packages/hoomd-blue.md +80 -0
  688. package/src/skills/science/references/packages/itensor.md +73 -0
  689. package/src/skills/science/references/packages/itensors-jl.md +73 -0
  690. package/src/skills/science/references/packages/jdftx.md +73 -0
  691. package/src/skills/science/references/packages/jobflow.md +80 -0
  692. package/src/skills/science/references/packages/kadanoffbaym-jl.md +73 -0
  693. package/src/skills/science/references/packages/kite.md +80 -0
  694. package/src/skills/science/references/packages/kratos.md +80 -0
  695. package/src/skills/science/references/packages/kwant.md +73 -0
  696. package/src/skills/science/references/packages/lammps.md +80 -0
  697. package/src/skills/science/references/packages/lightkurve.md +88 -0
  698. package/src/skills/science/references/packages/limix.md +73 -0
  699. package/src/skills/science/references/packages/maxwelllink.md +80 -0
  700. package/src/skills/science/references/packages/mcdc.md +73 -0
  701. package/src/skills/science/references/packages/meep.md +80 -0
  702. package/src/skills/science/references/packages/mfem.md +80 -0
  703. package/src/skills/science/references/packages/mitgcm.md +73 -0
  704. package/src/skills/science/references/packages/modflow6.md +73 -0
  705. package/src/skills/science/references/packages/molecool.md +73 -0
  706. package/src/skills/science/references/packages/mom6.md +73 -0
  707. package/src/skills/science/references/packages/moose.md +80 -0
  708. package/src/skills/science/references/packages/mpas-model.md +73 -0
  709. package/src/skills/science/references/packages/mujoco.md +73 -0
  710. package/src/skills/science/references/packages/mumax3.md +73 -0
  711. package/src/skills/science/references/packages/nekrs.md +80 -0
  712. package/src/skills/science/references/packages/nessi.md +73 -0
  713. package/src/skills/science/references/packages/nest-simulator.md +73 -0
  714. package/src/skills/science/references/packages/netket.md +73 -0
  715. package/src/skills/science/references/packages/neuron.md +73 -0
  716. package/src/skills/science/references/packages/nextflow.md +88 -0
  717. package/src/skills/science/references/packages/nwchem.md +88 -0
  718. package/src/skills/science/references/packages/openbabel.md +88 -0
  719. package/src/skills/science/references/packages/openems.md +80 -0
  720. package/src/skills/science/references/packages/openff-toolkit.md +88 -0
  721. package/src/skills/science/references/packages/openfoam-dev.md +80 -0
  722. package/src/skills/science/references/packages/openmc.md +73 -0
  723. package/src/skills/science/references/packages/openmm.md +80 -0
  724. package/src/skills/science/references/packages/openmoc.md +73 -0
  725. package/src/skills/science/references/packages/openmx.md +80 -0
  726. package/src/skills/science/references/packages/opensees.md +80 -0
  727. package/src/skills/science/references/packages/opensn.md +80 -0
  728. package/src/skills/science/references/packages/opm-simulators.md +73 -0
  729. package/src/skills/science/references/packages/oqupy.md +73 -0
  730. package/src/skills/science/references/packages/packmol.md +80 -0
  731. package/src/skills/science/references/packages/palabos.md +80 -0
  732. package/src/skills/science/references/packages/parflow.md +80 -0
  733. package/src/skills/science/references/packages/pennylane.md +88 -0
  734. package/src/skills/science/references/packages/perceval.md +73 -0
  735. package/src/skills/science/references/packages/phono3py.md +73 -0
  736. package/src/skills/science/references/packages/phonopy.md +73 -0
  737. package/src/skills/science/references/packages/photutils.md +88 -0
  738. package/src/skills/science/references/packages/picongpu.md +80 -0
  739. package/src/skills/science/references/packages/plink-ng.md +88 -0
  740. package/src/skills/science/references/packages/precice.md +73 -0
  741. package/src/skills/science/references/packages/psc.md +80 -0
  742. package/src/skills/science/references/packages/psi4.md +88 -0
  743. package/src/skills/science/references/packages/pybinding.md +73 -0
  744. package/src/skills/science/references/packages/pyfr.md +80 -0
  745. package/src/skills/science/references/packages/pyhf.md +73 -0
  746. package/src/skills/science/references/packages/pyiron_base.md +80 -0
  747. package/src/skills/science/references/packages/pylcp.md +73 -0
  748. package/src/skills/science/references/packages/pylith.md +80 -0
  749. package/src/skills/science/references/packages/pynbody.md +88 -0
  750. package/src/skills/science/references/packages/pysam.md +88 -0
  751. package/src/skills/science/references/packages/pyscf.md +88 -0
  752. package/src/skills/science/references/packages/q-e.md +73 -0
  753. package/src/skills/science/references/packages/qibo.md +73 -0
  754. package/src/skills/science/references/packages/qiskit.md +73 -0
  755. package/src/skills/science/references/packages/quantica-jl.md +73 -0
  756. package/src/skills/science/references/packages/quantumoptics-jl.md +73 -0
  757. package/src/skills/science/references/packages/quimb.md +73 -0
  758. package/src/skills/science/references/packages/qulacs.md +73 -0
  759. package/src/skills/science/references/packages/qutip.md +73 -0
  760. package/src/skills/science/references/packages/rdkit.md +88 -0
  761. package/src/skills/science/references/packages/rmg-py.md +73 -0
  762. package/src/skills/science/references/packages/root.md +73 -0
  763. package/src/skills/science/references/packages/scanpy.md +88 -0
  764. package/src/skills/science/references/packages/scikit-allel.md +88 -0
  765. package/src/skills/science/references/packages/scikit-bio.md +88 -0
  766. package/src/skills/science/references/packages/scqubits.md +73 -0
  767. package/src/skills/science/references/packages/scuff-em.md +80 -0
  768. package/src/skills/science/references/packages/scvi-tools.md +73 -0
  769. package/src/skills/science/references/packages/seissol.md +73 -0
  770. package/src/skills/science/references/packages/sfepy.md +80 -0
  771. package/src/skills/science/references/packages/sisl.md +73 -0
  772. package/src/skills/science/references/packages/smilei.md +80 -0
  773. package/src/skills/science/references/packages/snakemake.md +88 -0
  774. package/src/skills/science/references/packages/specfem3d-globe.md +80 -0
  775. package/src/skills/science/references/packages/specutils.md +88 -0
  776. package/src/skills/science/references/packages/spglib.md +80 -0
  777. package/src/skills/science/references/packages/squidpy.md +88 -0
  778. package/src/skills/science/references/packages/starry.md +88 -0
  779. package/src/skills/science/references/packages/strawberryfields.md +73 -0
  780. package/src/skills/science/references/packages/su2.md +80 -0
  781. package/src/skills/science/references/packages/sunny-jl.md +73 -0
  782. package/src/skills/science/references/packages/sw4.md +73 -0
  783. package/src/skills/science/references/packages/swift.md +88 -0
  784. package/src/skills/science/references/packages/tdnegf.md +73 -0
  785. package/src/skills/science/references/packages/tenpy.md +73 -0
  786. package/src/skills/science/references/packages/thermo.md +73 -0
  787. package/src/skills/science/references/packages/tkwant.md +73 -0
  788. package/src/skills/science/references/packages/tvb-root.md +73 -0
  789. package/src/skills/science/references/packages/uproot5.md +73 -0
  790. package/src/skills/science/references/packages/vampire.md +80 -0
  791. package/src/skills/science/references/packages/wannier_tools.md +73 -0
  792. package/src/skills/science/references/packages/warpx.md +80 -0
  793. package/src/skills/science/references/packages/wrf.md +73 -0
  794. package/src/skills/science/references/packages/xtb.md +88 -0
  795. package/src/skills/science/references/packages/yt.md +73 -0
  796. package/src/skills/science/references/science-task-brief-template.md +71 -0
  797. package/src/skills/scout/SKILL.md +83 -425
  798. package/src/skills/scout/references/literature-scout-template.md +5 -24
  799. package/src/skills/scout/references/operational-guidance.md +191 -0
  800. package/src/skills/scout/references/paper-triage-playbook.md +11 -35
  801. package/src/skills/write/SKILL.md +744 -1246
  802. package/src/skills/write/references/experiments_analysis_patterns.md +129 -0
  803. package/src/skills/write/references/oral_package_patterns.md +252 -0
  804. package/src/skills/write/references/oral_writing_principles.md +291 -0
  805. package/src/skills/write/references/section_rewrite_checklist.md +234 -0
  806. package/src/tui/dist/app/AppContainer.js +1314 -27
  807. package/src/tui/dist/components/Composer.js +26 -1
  808. package/src/tui/dist/components/ConfigScreen.js +2 -1
  809. package/src/tui/dist/components/InputPrompt.js +25 -9
  810. package/src/tui/dist/components/MainContent.js +18 -3
  811. package/src/tui/dist/components/QuestScreen.js +3 -2
  812. package/src/tui/dist/components/UtilityScreen.js +37 -0
  813. package/src/tui/dist/hooks/useSafeInput.js +10 -0
  814. package/src/tui/dist/index.js +13 -1
  815. package/src/tui/dist/layouts/DefaultAppLayout.js +11 -8
  816. package/src/tui/dist/lib/api.js +89 -1
  817. package/src/tui/package.json +1 -1
  818. package/src/ui/dist/assets/{AnalysisPlugin-BCKAfjba.js → AnalysisPlugin-CA94NGmI.js} +1 -1
  819. package/src/ui/dist/assets/CliPlugin-DHBzphZU.js +79 -0
  820. package/src/ui/dist/assets/CodeEditorPlugin-BOFwD2rn.js +2 -0
  821. package/src/ui/dist/assets/{CodeViewerPlugin-CbaFRrUU.js → CodeViewerPlugin-CqDpgjik.js} +4 -4
  822. package/src/ui/dist/assets/{DocViewerPlugin-DAjLVeQD.js → DocViewerPlugin-UDBgt8-4.js} +3 -3
  823. package/src/ui/dist/assets/GitCommitViewerPlugin-BmHtZ0bZ.js +6 -0
  824. package/src/ui/dist/assets/{GitDiffViewerPlugin-CQACjoAA.js → GitDiffViewerPlugin-CAxjNorQ.js} +2 -2
  825. package/src/ui/dist/assets/{GitSnapshotViewer-0r4nLPke.js → GitSnapshotViewer-CweA6VON.js} +2 -2
  826. package/src/ui/dist/assets/{ImageViewerPlugin-nBOmI2v_.js → ImageViewerPlugin-C8wHGvGN.js} +5 -5
  827. package/src/ui/dist/assets/LabPlugin-COyyLUol.js +32 -0
  828. package/src/ui/dist/assets/{LatexPlugin-ZwtV8pIp.js → LatexPlugin-BQjAaA5J.js} +4 -4
  829. package/src/ui/dist/assets/{MarkdownViewerPlugin-DKqVfKyW.js → MarkdownViewerPlugin-Dy1NE2dI.js} +3 -3
  830. package/src/ui/dist/assets/{MarketplacePlugin-BwxStZ9D.js → MarketplacePlugin-DMIZtEJ2.js} +2 -2
  831. package/src/ui/dist/assets/NotebookEditor-CFHMq_Qt.js +91 -0
  832. package/src/ui/dist/assets/{NotebookEditor-DB9N_T9q.js → NotebookEditor-WFyd8Ybt.js} +3 -3
  833. package/src/ui/dist/assets/{PdfLoader-eWBONbQP.js → PdfLoader-CLE5u5TS.js} +3 -3
  834. package/src/ui/dist/assets/{PdfMarkdownPlugin-D22YOZL3.js → PdfMarkdownPlugin-_iNK_H83.js} +1 -1
  835. package/src/ui/dist/assets/PdfViewerPlugin-DgWsbInT.js +22 -0
  836. package/src/ui/dist/assets/SearchPlugin-DrZmn5iw.js +11 -0
  837. package/src/ui/dist/assets/{TextViewerPlugin-C5xqeeUH.js → TextViewerPlugin-D1-T3aC7.js} +4 -4
  838. package/src/ui/dist/assets/branding/runner-claude.svg +107 -0
  839. package/src/ui/dist/assets/branding/runner-codex.svg +10 -0
  840. package/src/ui/dist/assets/branding/runner-kimi.svg +14 -0
  841. package/src/ui/dist/assets/branding/runner-opencode.svg +7 -0
  842. package/src/ui/dist/assets/cli-store-CoZ-x5Ip.js +1 -0
  843. package/src/ui/dist/assets/{code-WlFHE7z_.js → code-DbsmSd3Y.js} +1 -1
  844. package/src/ui/dist/assets/file-diff-panel-DsvyRz47.js +1 -0
  845. package/src/ui/dist/assets/{wrap-text-BC-Hltpd.js → file-jump-queue-DeQBikaw.js} +3 -3
  846. package/src/ui/dist/assets/{file-socket-CfQPKQKj.js → file-socket-DA5XIx88.js} +1 -1
  847. package/src/ui/dist/assets/fonts/ds-fonts.css +50 -4
  848. package/src/ui/dist/assets/images/deepxiv/register-guide.png +0 -0
  849. package/src/ui/dist/assets/index-39vY9LmZ.js +1 -0
  850. package/src/ui/dist/assets/{index-CwNu1aH4.js → index-BsO46tJA.js} +1 -1
  851. package/src/ui/dist/assets/index-CHzJ2xtB.js +3530 -0
  852. package/src/ui/dist/assets/index-DH-zxoZ3.css +33 -0
  853. package/src/ui/dist/assets/{plugin-notebook-HbW2K-1c.js → plugin-notebook-JRhysCqj.js} +2 -2
  854. package/src/ui/dist/assets/{project-sync-C9IdzdZW.js → project-sync-DPmWKmKD.js} +1 -1
  855. package/src/ui/dist/assets/{zoom-out-E_gaeAxL.js → zoom-out-DAukFWen.js} +3 -3
  856. package/src/ui/dist/index.html +3 -3
  857. package/src/skills/analysis-campaign/references/artifact-orchestration.md +0 -58
  858. package/src/skills/baseline/references/memory-playbook.md +0 -40
  859. package/src/skills/baseline/references/publishable-baseline-package.md +0 -30
  860. package/src/skills/write/references/outline-evidence-contract-example.md +0 -107
  861. package/src/skills/write/references/paper-experiment-matrix-template.md +0 -131
  862. package/src/skills/write/references/paper-section-playbook.md +0 -64
  863. package/src/skills/write/references/reviewer-first-writing.md +0 -64
  864. package/src/skills/write/references/revision-checklist.md +0 -70
  865. package/src/skills/write/references/section-contracts.md +0 -82
  866. package/src/skills/write/references/sentence-level-proofing.md +0 -49
  867. package/src/ui/dist/assets/AiManusChatView-Bv-Z8YpU.js +0 -204
  868. package/src/ui/dist/assets/CliPlugin-BCKcpc35.js +0 -109
  869. package/src/ui/dist/assets/CodeEditorPlugin-DbOfSJ8K.js +0 -2
  870. package/src/ui/dist/assets/GitCommitViewerPlugin-CIUqbUDO.js +0 -1
  871. package/src/ui/dist/assets/LabCopilotPanel-BHxOxF4z.js +0 -14
  872. package/src/ui/dist/assets/LabPlugin-BKoZGs95.js +0 -22
  873. package/src/ui/dist/assets/NotebookEditor-BEQhaQbt.js +0 -81
  874. package/src/ui/dist/assets/PdfViewerPlugin-c-RK9DLM.js +0 -17
  875. package/src/ui/dist/assets/SearchPlugin-CxF9ytAx.js +0 -16
  876. package/src/ui/dist/assets/VNCViewer-BoLGLnHz.js +0 -11
  877. package/src/ui/dist/assets/bot-DREQOxzP.js +0 -6
  878. package/src/ui/dist/assets/chevron-up-C9Qpx4DE.js +0 -6
  879. package/src/ui/dist/assets/file-content-BZMz3RYp.js +0 -1
  880. package/src/ui/dist/assets/file-diff-panel-CQhw0jS2.js +0 -1
  881. package/src/ui/dist/assets/file-jump-queue-DA-SdG__.js +0 -1
  882. package/src/ui/dist/assets/git-commit-horizontal-DxZ8DCZh.js +0 -6
  883. package/src/ui/dist/assets/image-Bgl4VIyx.js +0 -6
  884. package/src/ui/dist/assets/index-BpV6lusQ.css +0 -33
  885. package/src/ui/dist/assets/index-CBNVuWcP.js +0 -2496
  886. package/src/ui/dist/assets/index-DrUnlf6K.js +0 -1
  887. package/src/ui/dist/assets/index-NW-h8VzN.js +0 -1
  888. package/src/ui/dist/assets/pdf-effect-queue-J8OnM0jE.js +0 -6
  889. package/src/ui/dist/assets/popover-CLc0pPP8.js +0 -1
  890. package/src/ui/dist/assets/select-Cs2PmzwL.js +0 -11
  891. package/src/ui/dist/assets/sigma-ClKcHAXm.js +0 -6
  892. package/src/ui/dist/assets/trash-DwpbFr3w.js +0 -11
  893. package/src/ui/dist/assets/useCliAccess-NQ8m0Let.js +0 -1
  894. package/src/ui/dist/assets/useFileDiffOverlay-FuhcnKiw.js +0 -1
@@ -2,11 +2,14 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
+ import shlex
6
+ import shutil
5
7
  import subprocess
6
8
  import tempfile
7
9
  from copy import deepcopy
8
10
  from pathlib import Path
9
11
  from urllib.error import URLError
12
+ from urllib.parse import urlencode
10
13
  from urllib.request import Request
11
14
 
12
15
  from ..codex_cli_compat import (
@@ -21,6 +24,7 @@ from ..codex_cli_compat import (
21
24
  normalize_codex_reasoning_effort,
22
25
  provider_base_url_looks_local,
23
26
  )
27
+ from ..kimi_cli_compat import materialize_kimi_runtime_home
24
28
  from ..connector.connector_profiles import PROFILEABLE_CONNECTOR_NAMES, list_connector_profiles, normalize_connector_config
25
29
  from ..connector_runtime import build_discovered_target, infer_connector_transport
26
30
  from ..home import repo_root
@@ -49,8 +53,9 @@ from ..connector.qq_profiles import (
49
53
  )
50
54
  from ..connector.weixin_support import normalize_weixin_base_url, normalize_weixin_cdn_base_url
51
55
  from ..network import urlopen_with_proxy as urlopen
56
+ from ..runners.metadata import get_runner_metadata, list_builtin_runner_names
52
57
  from ..runners.runtime_overrides import apply_codex_runtime_overrides, apply_runners_runtime_overrides
53
- from ..shared import read_json, read_text, read_yaml, resolve_runner_binary, run_command, sha256_text, utc_now, which, write_text, write_yaml
58
+ from ..shared import ensure_utf8_subprocess_env, read_json, read_text, read_yaml, resolve_runner_binary, run_command, sha256_text, utc_now, utf8_text_subprocess_kwargs, which, write_json, write_text, write_yaml
54
59
  from .models import (
55
60
  CONFIG_NAMES,
56
61
  OPTIONAL_CONFIG_NAMES,
@@ -211,31 +216,83 @@ class ConfigManager:
211
216
  return prepared
212
217
 
213
218
  def _invalidate_codex_bootstrap_state_if_runner_changed(self, previous: dict, current: dict) -> None:
214
- previous_codex = previous.get("codex") if isinstance(previous.get("codex"), dict) else {}
215
- current_codex = current.get("codex") if isinstance(current.get("codex"), dict) else {}
216
- tracked_keys = (
217
- "binary",
218
- "config_dir",
219
- "profile",
220
- "model",
221
- "model_reasoning_effort",
222
- "approval_policy",
223
- "sandbox_mode",
224
- "env",
225
- )
226
- if all(previous_codex.get(key) == current_codex.get(key) for key in tracked_keys):
219
+ tracked_keys_by_runner = {
220
+ "codex": (
221
+ "binary",
222
+ "config_dir",
223
+ "profile",
224
+ "model",
225
+ "model_reasoning_effort",
226
+ "approval_policy",
227
+ "sandbox_mode",
228
+ "env",
229
+ "mcp_tool_timeout_sec",
230
+ ),
231
+ "claude": (
232
+ "binary",
233
+ "config_dir",
234
+ "model",
235
+ "permission_mode",
236
+ "mcp_timeout_ms",
237
+ "mcp_tool_timeout_ms",
238
+ "env",
239
+ ),
240
+ "kimi": (
241
+ "binary",
242
+ "config_dir",
243
+ "model",
244
+ "agent",
245
+ "thinking",
246
+ "yolo",
247
+ "mcp_tool_timeout_ms",
248
+ "env",
249
+ ),
250
+ "opencode": (
251
+ "binary",
252
+ "config_dir",
253
+ "model",
254
+ "permission_mode",
255
+ "default_agent",
256
+ "variant",
257
+ "mcp_timeout_ms",
258
+ "env",
259
+ ),
260
+ }
261
+ changed_runners: list[str] = []
262
+ for runner_name, tracked_keys in tracked_keys_by_runner.items():
263
+ previous_runner = previous.get(runner_name) if isinstance(previous.get(runner_name), dict) else {}
264
+ current_runner = current.get(runner_name) if isinstance(current.get(runner_name), dict) else {}
265
+ if all(previous_runner.get(key) == current_runner.get(key) for key in tracked_keys):
266
+ continue
267
+ changed_runners.append(runner_name)
268
+ if not changed_runners:
227
269
  return
228
270
  config = self.load_named_normalized("config")
229
271
  bootstrap = config.get("bootstrap") if isinstance(config.get("bootstrap"), dict) else {}
230
- bootstrap["codex_ready"] = False
231
- bootstrap["codex_last_checked_at"] = utc_now()
232
- bootstrap["codex_last_result"] = {
233
- "ok": False,
234
- "summary": "Codex runner configuration changed. A new startup probe is required.",
235
- "warnings": [],
236
- "errors": [],
237
- "guidance": [],
238
- }
272
+ runner_readiness = bootstrap.get("runner_readiness") if isinstance(bootstrap.get("runner_readiness"), dict) else {}
273
+ checked_at = utc_now()
274
+ for runner_name in changed_runners:
275
+ try:
276
+ runner_label = get_runner_metadata(runner_name).label
277
+ except KeyError:
278
+ runner_label = runner_name
279
+ summary = f"{runner_label} runner configuration changed. A new startup probe is required."
280
+ runner_readiness[runner_name] = {
281
+ "ready": False,
282
+ "last_checked_at": checked_at,
283
+ "last_result": {
284
+ "ok": False,
285
+ "summary": summary,
286
+ "warnings": [],
287
+ "errors": [],
288
+ "guidance": [],
289
+ },
290
+ }
291
+ bootstrap["runner_readiness"] = runner_readiness
292
+ codex_state = runner_readiness.get("codex") if isinstance(runner_readiness.get("codex"), dict) else {}
293
+ bootstrap["codex_ready"] = bool(codex_state.get("ready", False))
294
+ bootstrap["codex_last_checked_at"] = codex_state.get("last_checked_at")
295
+ bootstrap["codex_last_result"] = codex_state.get("last_result") if isinstance(codex_state.get("last_result"), dict) else {}
239
296
  config["bootstrap"] = bootstrap
240
297
  self.save_named_text("config", self.render_named_payload("config", config))
241
298
 
@@ -476,12 +533,12 @@ The **Test** button checks:
476
533
 
477
534
  This is a safe local smoke test.
478
535
 
479
- ## Codex startup gate
536
+ ## Runner startup gate
480
537
 
481
- - `bootstrap.codex_ready` starts as `false`
482
- - the launcher runs a real Codex hello probe before first daemon start
483
- - once Codex answers correctly, DeepScientist flips this flag to `true`
484
- - if the probe fails, DeepScientist writes the failure summary back into config and blocks startup
538
+ - the launcher runs a real hello probe for the selected runner before first daemon start
539
+ - `codex`, `claude`, `kimi`, and `opencode` can each record readiness under `bootstrap.runner_readiness`
540
+ - if the selected runner fails, DeepScientist writes the failure summary back into config and blocks only that requested startup path
541
+ - you can start with the default runner first, then configure or switch Claude Code / Kimi Code / OpenCode from Settings
485
542
 
486
543
  ## Figure and chart style policy
487
544
 
@@ -497,15 +554,16 @@ This page edits `{home_text}/config/runners.yaml`.
497
554
  ## Recommended v1 choice
498
555
 
499
556
  - keep `codex.enabled: true`
500
- - keep `claude.enabled: false`
501
- - `claude` remains TODO / reserved in the current open-source release and is not runnable yet
557
+ - enable whichever runners you actually plan to use (`codex`, `claude`, `kimi`, `opencode`)
558
+ - keep the others disabled if their local CLI or credentials are not ready yet
502
559
  - set `codex.profile` only when your Codex CLI uses a named provider profile such as `m27`
503
560
  - when you launch DeepScientist ad hoc with a provider profile, you can also use `ds --codex-profile <name>`
504
561
  - when you want a one-off Codex binary override, you can also use `ds --codex /absolute/path/to/codex`
505
562
  - keep `codex.model_reasoning_effort: xhigh` unless you explicitly want a lighter default
506
563
  - keep `codex.retry_on_failure: true` so transient Codex failures can resume automatically
507
- - keep retry timing near `10s / 6x / 1800s max` so Codex backs off exponentially and the last retry waits about 30 minutes
508
- - DeepScientist hard-limits one turn to at most `5` total attempts, even if the config says more
564
+ - keep retry timing near `10s / 6x / 1800s max` so Codex backs off exponentially and the final retries sit at the 30-minute cap
565
+ - DeepScientist hard-limits one turn to at most `7` total attempts, even if the config says more
566
+ - one-off diagnostics can target a runner without permanently enabling it: `ds doctor --runner claude`, `ds doctor --runner kimi`, or `ds doctor --runner opencode`
509
567
 
510
568
  ## Test behavior
511
569
 
@@ -513,7 +571,7 @@ The **Test** button checks:
513
571
 
514
572
  - whether the configured runner binaries are on PATH
515
573
  - whether disabled runners are intentionally skipped
516
- - for Codex, it also runs a real hello probe so login problems, profile misconfiguration, and first-run setup issues surface before quest execution
574
+ - for enabled runners, it also runs a real hello probe so login problems, profile misconfiguration, and first-run setup issues surface before quest execution
517
575
  - it does not simulate the full failure/retry loop, so use quest runtime logs when debugging recovery behavior
518
576
  """
519
577
  if name == "plugins":
@@ -607,21 +665,159 @@ Use **Test** when the file exposes runtime dependencies.
607
665
  rendered = self.render_named_payload(name, payload)
608
666
  return self.test_named_text(name, rendered, live=live, delivery_targets=delivery_targets)
609
667
 
610
- def probe_codex_bootstrap(self, *, persist: bool = False, payload: dict | None = None) -> dict:
611
- runners_payload = payload if isinstance(payload, dict) else self.load_named_normalized("runners")
612
- codex_payload = runners_payload.get("codex") if isinstance(runners_payload.get("codex"), dict) else {}
613
- result = self._probe_codex_runner(codex_payload)
668
+ def test_deepxiv_payload(self, payload: dict | None = None) -> dict:
669
+ normalized = self._normalize_named_payload("config", payload if isinstance(payload, dict) else self.load_named_normalized("config"))
670
+ literature = normalized.get("literature") if isinstance(normalized.get("literature"), dict) else {}
671
+ deepxiv = literature.get("deepxiv") if isinstance(literature.get("deepxiv"), dict) else {}
672
+ base_url = str(deepxiv.get("base_url") or "https://data.rag.ac.cn").strip() or "https://data.rag.ac.cn"
673
+ direct_token = str(deepxiv.get("token") or "").strip()
674
+ token_env_name = str(deepxiv.get("token_env") or "").strip()
675
+ env_token = str(os.environ.get(token_env_name) or "").strip() if token_env_name else ""
676
+ resolved_token = direct_token or env_token
677
+ query = "transformers"
678
+ result_size = max(1, int(deepxiv.get("default_result_size") or 10))
679
+ preview_characters = max(200, int(deepxiv.get("preview_characters") or 1200))
680
+ request_timeout_seconds = max(3, int(deepxiv.get("request_timeout_seconds") or 20))
681
+ details = {
682
+ "base_url": base_url,
683
+ "query": query,
684
+ "result_size": result_size,
685
+ "preview_characters": preview_characters,
686
+ "request_timeout_seconds": request_timeout_seconds,
687
+ "token_source": "direct_token" if direct_token else ("env" if env_token else "missing"),
688
+ "token_env": token_env_name or None,
689
+ }
690
+ if not resolved_token:
691
+ return {
692
+ "ok": False,
693
+ "summary": "DeepXiv test failed: token is missing.",
694
+ "warnings": [],
695
+ "errors": ["Provide a DeepXiv token before running the test."],
696
+ "details": details,
697
+ "results": [],
698
+ "preview": "",
699
+ }
700
+ url = f"{base_url.rstrip('/')}/arxiv/?{urlencode({'type': 'retrieve', 'query': query, 'size': str(result_size)})}"
701
+ request = Request(
702
+ url,
703
+ headers={
704
+ "Accept": "application/json",
705
+ "Authorization": f"Bearer {resolved_token}",
706
+ "User-Agent": "DeepScientist/DeepXivTest",
707
+ },
708
+ )
709
+ try:
710
+ with urlopen(request, timeout=request_timeout_seconds) as response: # noqa: S310
711
+ response_text = response.read().decode("utf-8", errors="replace")
712
+ except Exception as exc:
713
+ details["request_url"] = url
714
+ return {
715
+ "ok": False,
716
+ "summary": "DeepXiv test request failed.",
717
+ "warnings": [],
718
+ "errors": [str(exc)],
719
+ "details": details,
720
+ "results": [],
721
+ "preview": "",
722
+ }
723
+ try:
724
+ parsed = json.loads(response_text)
725
+ except json.JSONDecodeError:
726
+ preview = response_text[:preview_characters].rstrip()
727
+ if len(response_text) > preview_characters:
728
+ preview = f"{preview}\n...[truncated]"
729
+ details["request_url"] = url
730
+ return {
731
+ "ok": False,
732
+ "summary": "DeepXiv test returned invalid JSON.",
733
+ "warnings": [],
734
+ "errors": ["DeepXiv returned invalid JSON."],
735
+ "details": details,
736
+ "results": [],
737
+ "preview": preview,
738
+ }
739
+ results = parsed.get("results") if isinstance(parsed.get("results"), list) else []
740
+ if not results and isinstance(parsed.get("result"), list):
741
+ results = parsed.get("result") or []
742
+ total = parsed.get("total")
743
+ if total is None:
744
+ total = parsed.get("total_count")
745
+ preview_payload = {
746
+ "total": total,
747
+ "took": parsed.get("took"),
748
+ "results": results[: min(3, len(results))],
749
+ }
750
+ preview = json.dumps(preview_payload, ensure_ascii=False, indent=2)
751
+ if len(preview) > preview_characters:
752
+ preview = f"{preview[:preview_characters].rstrip()}\n...[truncated]"
753
+ details.update(
754
+ {
755
+ "request_url": url,
756
+ "total": total,
757
+ "result_count": len(results),
758
+ "first_title": str((results[0] or {}).get("title") or "").strip() if results else None,
759
+ }
760
+ )
761
+ ok = len(results) > 0
762
+ return {
763
+ "ok": ok,
764
+ "summary": "DeepXiv returned search results for `transformers`." if ok else "DeepXiv returned no search results for `transformers`.",
765
+ "warnings": [],
766
+ "errors": [] if ok else ["No results were returned for `transformers`."],
767
+ "details": details,
768
+ "results": results[:5],
769
+ "preview": preview,
770
+ }
771
+
772
+ def probe_runner_bootstrap(self, runner_name: str, *, persist: bool = False, payload: dict | None = None) -> dict:
773
+ normalized_runner = str(runner_name or "codex").strip().lower() or "codex"
774
+ runners_payload = payload if isinstance(payload, dict) else self.load_runners_config()
775
+ runner_payload = runners_payload.get(normalized_runner) if isinstance(runners_payload.get(normalized_runner), dict) else {}
776
+ if normalized_runner == "codex":
777
+ result = self._probe_codex_runner(runner_payload)
778
+ elif normalized_runner == "claude":
779
+ result = self._probe_claude_runner(runner_payload)
780
+ elif normalized_runner == "kimi":
781
+ result = self._probe_kimi_runner(runner_payload)
782
+ elif normalized_runner == "opencode":
783
+ result = self._probe_opencode_runner(runner_payload)
784
+ else:
785
+ raise KeyError(f"Unknown runner `{normalized_runner}`.")
614
786
  if persist:
615
- self._persist_codex_bootstrap_result(result)
787
+ self._persist_runner_bootstrap_result(normalized_runner, result)
616
788
  return result
617
789
 
618
- def codex_bootstrap_state(self) -> dict:
790
+ def runner_bootstrap_state(self, runner_name: str) -> dict:
791
+ normalized_runner = str(runner_name or "codex").strip().lower() or "codex"
619
792
  config = self.load_named_normalized("config")
620
793
  bootstrap = config.get("bootstrap") if isinstance(config.get("bootstrap"), dict) else {}
794
+ runner_readiness = bootstrap.get("runner_readiness") if isinstance(bootstrap.get("runner_readiness"), dict) else {}
795
+ runner_state = runner_readiness.get(normalized_runner) if isinstance(runner_readiness.get(normalized_runner), dict) else {}
796
+ if normalized_runner == "codex" and not runner_state:
797
+ runner_state = {
798
+ "ready": bool(bootstrap.get("codex_ready", False)),
799
+ "last_checked_at": bootstrap.get("codex_last_checked_at"),
800
+ "last_result": bootstrap.get("codex_last_result") if isinstance(bootstrap.get("codex_last_result"), dict) else {},
801
+ }
802
+ return {
803
+ "runner": normalized_runner,
804
+ "ready": bool(runner_state.get("ready", False)),
805
+ "last_checked_at": runner_state.get("last_checked_at"),
806
+ "last_result": runner_state.get("last_result") if isinstance(runner_state.get("last_result"), dict) else {},
807
+ }
808
+
809
+ def runner_readiness_map(self) -> dict[str, dict[str, Any]]:
810
+ return {name: self.runner_bootstrap_state(name) for name in list_builtin_runner_names()}
811
+
812
+ def probe_codex_bootstrap(self, *, persist: bool = False, payload: dict | None = None) -> dict:
813
+ return self.probe_runner_bootstrap("codex", persist=persist, payload=payload)
814
+
815
+ def codex_bootstrap_state(self) -> dict:
816
+ state = self.runner_bootstrap_state("codex")
621
817
  return {
622
- "codex_ready": bool(bootstrap.get("codex_ready", False)),
623
- "codex_last_checked_at": bootstrap.get("codex_last_checked_at"),
624
- "codex_last_result": bootstrap.get("codex_last_result") if isinstance(bootstrap.get("codex_last_result"), dict) else {},
818
+ "codex_ready": bool(state.get("ready")),
819
+ "codex_last_checked_at": state.get("last_checked_at"),
820
+ "codex_last_result": state.get("last_result") if isinstance(state.get("last_result"), dict) else {},
625
821
  }
626
822
 
627
823
  def git_readiness(self) -> dict:
@@ -701,7 +897,8 @@ Use **Test** when the file exposes runtime dependencies.
701
897
 
702
898
  def _test_runners_payload(self, payload: dict, *, live: bool) -> dict:
703
899
  items = []
704
- for name, config in payload.items():
900
+ normalized_payload = apply_runners_runtime_overrides(self._normalize_named_payload("runners", payload))
901
+ for name, config in normalized_payload.items():
705
902
  if not isinstance(config, dict):
706
903
  continue
707
904
  enabled = bool(config.get("enabled", False))
@@ -724,8 +921,8 @@ Use **Test** when the file exposes runtime dependencies.
724
921
  "live_probe_executed": False,
725
922
  },
726
923
  }
727
- if enabled and name == "codex" and exists and live:
728
- probe = self._probe_codex_runner(config)
924
+ if enabled and exists and live:
925
+ probe = self.probe_runner_bootstrap(name, persist=False, payload=normalized_payload)
729
926
  item["ok"] = bool(probe.get("ok"))
730
927
  item["warnings"] = [*warnings, *list(probe.get("warnings") or [])]
731
928
  item["errors"] = list(probe.get("errors") or [])
@@ -1221,7 +1418,7 @@ Use **Test** when the file exposes runtime dependencies.
1221
1418
  def _codex_runner_env(config: dict) -> dict[str, str]:
1222
1419
  raw_env = config.get("env")
1223
1420
  if not isinstance(raw_env, dict):
1224
- return {}
1421
+ return ensure_utf8_subprocess_env({})
1225
1422
  resolved: dict[str, str] = {}
1226
1423
  for key, value in raw_env.items():
1227
1424
  env_key = str(key or "").strip()
@@ -1231,7 +1428,7 @@ Use **Test** when the file exposes runtime dependencies.
1231
1428
  if env_value == "":
1232
1429
  continue
1233
1430
  resolved[env_key] = env_value
1234
- return resolved
1431
+ return ensure_utf8_subprocess_env(resolved)
1235
1432
 
1236
1433
  def _prepare_codex_probe_home(
1237
1434
  self,
@@ -1324,6 +1521,14 @@ Use **Test** when the file exposes runtime dependencies.
1324
1521
  hints.insert(0, f"Your current provider config uses `wire_api = \"{wire_api}\"`; switch it to `wire_api = \"responses\"` first.")
1325
1522
  return hints
1326
1523
 
1524
+ @staticmethod
1525
+ def _codex_direct_hello_probe_command(*, profile: str = "") -> str:
1526
+ profile_args = f" --profile {shlex.quote(profile)}" if profile else ""
1527
+ return (
1528
+ "printf 'Reply with exactly HELLO.' | "
1529
+ f"codex --search{profile_args} exec --json --cd /tmp --skip-git-repo-check -"
1530
+ )
1531
+
1327
1532
  @staticmethod
1328
1533
  def _missing_provider_env_guidance(
1329
1534
  *,
@@ -1343,7 +1548,8 @@ Use **Test** when the file exposes runtime dependencies.
1343
1548
  "Also add `requires_openai_auth = false` to that local provider profile so DeepScientist can remove conflicting `OPENAI_*` auth variables."
1344
1549
  )
1345
1550
  guidance.append(
1346
- f"Before retrying DeepScientist, run a real request such as `codex exec --profile {profile} --json --cd /tmp --skip-git-repo-check -` and verify it returns `HELLO`."
1551
+ "Before retrying DeepScientist, run a real request such as "
1552
+ f"`{ConfigManager._codex_direct_hello_probe_command(profile=profile)}` and verify it returns `HELLO`."
1347
1553
  )
1348
1554
  return guidance
1349
1555
 
@@ -1383,7 +1589,52 @@ Use **Test** when the file exposes runtime dependencies.
1383
1589
  },
1384
1590
  )
1385
1591
 
1386
- def _codex_probe_failure_guidance(self, config: dict) -> tuple[list[str], list[str]]:
1592
+ @staticmethod
1593
+ def _codex_probe_text_looks_auth_related(stdout_text: str, stderr_text: str) -> bool:
1594
+ haystack = f"{stdout_text}\n{stderr_text}".lower()
1595
+ markers = (
1596
+ "please login",
1597
+ "not logged in",
1598
+ "login required",
1599
+ "authentication required",
1600
+ "auth required",
1601
+ "oauth",
1602
+ "unauthenticated",
1603
+ "missing credentials",
1604
+ "no credentials",
1605
+ )
1606
+ return any(marker in haystack for marker in markers)
1607
+
1608
+ @staticmethod
1609
+ def _codex_probe_text_looks_network_related(stdout_text: str, stderr_text: str) -> bool:
1610
+ haystack = f"{stdout_text}\n{stderr_text}".lower()
1611
+ markers = (
1612
+ "connection refused",
1613
+ "connection reset",
1614
+ "connection timed out",
1615
+ "network is unreachable",
1616
+ "name or service not known",
1617
+ "temporary failure in name resolution",
1618
+ "dns",
1619
+ "proxy",
1620
+ "tls",
1621
+ "certificate",
1622
+ "ssl",
1623
+ "timeout",
1624
+ "timed out",
1625
+ "econnreset",
1626
+ "econnrefused",
1627
+ "enotfound",
1628
+ )
1629
+ return any(marker in haystack for marker in markers)
1630
+
1631
+ def _codex_probe_failure_guidance(
1632
+ self,
1633
+ config: dict,
1634
+ *,
1635
+ stdout_text: str = "",
1636
+ stderr_text: str = "",
1637
+ ) -> tuple[list[str], list[str]]:
1387
1638
  profile = self._codex_profile_name(config)
1388
1639
  config_dir = str(config.get("config_dir") or "~/.codex").strip()
1389
1640
  metadata = active_provider_metadata_from_home(config_dir, profile=profile or None) if config_dir else {}
@@ -1395,7 +1646,7 @@ Use **Test** when the file exposes runtime dependencies.
1395
1646
  f"Codex profile `{profile}` did not complete the startup hello probe successfully.",
1396
1647
  ],
1397
1648
  [
1398
- f"Run `codex exec --profile {profile} --json --cd /tmp --skip-git-repo-check -` in a terminal and confirm that a real `HELLO` request succeeds.",
1649
+ f"Run `{self._codex_direct_hello_probe_command(profile=profile)}` in a terminal and confirm that a real `HELLO` request succeeds.",
1399
1650
  "If the profile uses a custom provider, make sure its API key, Base URL, and model configuration are available to Codex.",
1400
1651
  "If the provider expects the model from the Codex profile itself, set `model: inherit` in `~/DeepScientist/config/runners.yaml`.",
1401
1652
  *provider_hints,
@@ -1403,14 +1654,49 @@ Use **Test** when the file exposes runtime dependencies.
1403
1654
  "Then run `ds doctor` and start DeepScientist again.",
1404
1655
  ],
1405
1656
  )
1657
+ if self._codex_probe_text_looks_auth_related(stdout_text, stderr_text):
1658
+ return (
1659
+ [
1660
+ "Codex reported an authentication or first-run setup problem during the startup hello probe.",
1661
+ "Run `codex login` (or just `codex`) once and complete login before starting DeepScientist.",
1662
+ ],
1663
+ [
1664
+ "Run `codex login` (or just `codex`) in a terminal and complete login or first-run setup.",
1665
+ "Then run `printf 'Reply with exactly HELLO.' | codex --search exec --json --cd /tmp --skip-git-repo-check -` and confirm the real request succeeds.",
1666
+ "If login succeeds but the direct probe still fails, check the configured model, provider profile, proxy, and Codex account access.",
1667
+ "Then run `ds doctor` and start DeepScientist again.",
1668
+ ],
1669
+ )
1670
+ if self._codex_model_unavailable(stdout_text, stderr_text):
1671
+ return (
1672
+ [
1673
+ "Codex authentication may be working, but the configured startup probe model was not accepted.",
1674
+ ],
1675
+ [
1676
+ "Run `printf 'Reply with exactly HELLO.' | codex --search exec --json --cd /tmp --skip-git-repo-check -` in the same shell and confirm the current Codex default model works.",
1677
+ "Set `runners.codex.model: inherit` in `~/DeepScientist/config/runners.yaml`, or set it to a model that your Codex account can actually use.",
1678
+ "Then run `ds doctor` and start DeepScientist again.",
1679
+ ],
1680
+ )
1681
+ if self._codex_probe_text_looks_network_related(stdout_text, stderr_text):
1682
+ return (
1683
+ [
1684
+ "Codex CLI was found, but the real startup hello request appears to have failed at the network, proxy, TLS, or provider layer.",
1685
+ ],
1686
+ [
1687
+ "Run `printf 'Reply with exactly HELLO.' | codex --search exec --json --cd /tmp --skip-git-repo-check -` from the same shell and verify the request succeeds.",
1688
+ "If this host needs a proxy, export `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` before launching `ds`; for managed or supervised runs, also put required environment variables under `runners.codex.env`.",
1689
+ "Then run `ds doctor` and start DeepScientist again.",
1690
+ ],
1691
+ )
1406
1692
  return (
1407
1693
  [
1408
- "Run `codex login` (or just `codex`) once and complete login before starting DeepScientist.",
1694
+ "Codex CLI was found, but its real startup hello request did not complete successfully.",
1409
1695
  ],
1410
1696
  [
1411
- "Run `codex login` (or just `codex`) in a terminal and complete login or first-run setup.",
1412
- "If `codex` is missing, install it explicitly with `npm install -g @openai/codex`.",
1413
- "If the configured model is not available to your Codex account, update `~/DeepScientist/config/runners.yaml` and try again.",
1697
+ "Run `printf 'Reply with exactly HELLO.' | codex --search exec --json --cd /tmp --skip-git-repo-check -` in the same shell and inspect the Codex stderr/stdout.",
1698
+ "If that direct command succeeds but `ds doctor` fails, compare `which codex`, `CODEX_HOME`, proxy variables, and `~/DeepScientist/config/runners.yaml`.",
1699
+ "If the configured model is not available to your Codex account, set `runners.codex.model: inherit` or another accessible model.",
1414
1700
  "Then run `ds doctor` and start DeepScientist again.",
1415
1701
  ],
1416
1702
  )
@@ -1533,8 +1819,8 @@ Use **Test** when the file exposes runtime dependencies.
1533
1819
  approval_policy = str(config.get("approval_policy") or "on-request").strip()
1534
1820
  sandbox_mode = str(config.get("sandbox_mode") or "workspace-write").strip()
1535
1821
 
1536
- env = os.environ.copy()
1537
- env.update(self._codex_runner_env(config))
1822
+ env = ensure_utf8_subprocess_env(os.environ.copy())
1823
+ env.update(self._claude_auth_runner_env(self._codex_runner_env(config)))
1538
1824
  config_dir = str(config.get("config_dir") or "~/.codex").strip()
1539
1825
  probe_home_handle: tempfile.TemporaryDirectory[str] | None = None
1540
1826
  compatibility_warnings: list[str] = []
@@ -1593,10 +1879,10 @@ Use **Test** when the file exposes runtime dependencies.
1593
1879
  input=prompt,
1594
1880
  cwd=str(repo_root()),
1595
1881
  env=env,
1596
- text=True,
1597
1882
  capture_output=True,
1598
1883
  timeout=90,
1599
1884
  check=False,
1885
+ **utf8_text_subprocess_kwargs(),
1600
1886
  )
1601
1887
  except subprocess.TimeoutExpired as exc:
1602
1888
  return command, None, exc
@@ -1604,25 +1890,32 @@ Use **Test** when the file exposes runtime dependencies.
1604
1890
 
1605
1891
  command, result, timeout_error = run_probe_once(effective_model)
1606
1892
  if timeout_error is not None:
1893
+ stdout_text = str(timeout_error.stdout or "")
1894
+ stderr_text = str(timeout_error.stderr or "")
1607
1895
  details.update(
1608
1896
  {
1609
1897
  "exit_code": None,
1610
- "stdout_excerpt": self._compact_probe_text(timeout_error.stdout or ""),
1611
- "stderr_excerpt": self._compact_probe_text(timeout_error.stderr or ""),
1898
+ "stdout_excerpt": self._compact_probe_text(stdout_text),
1899
+ "stderr_excerpt": self._compact_probe_text(stderr_text),
1612
1900
  "probe_command": command,
1613
1901
  }
1614
1902
  )
1903
+ failure_errors, failure_guidance = self._codex_probe_failure_guidance(
1904
+ config,
1905
+ stdout_text=stdout_text,
1906
+ stderr_text=stderr_text,
1907
+ )
1615
1908
  return {
1616
1909
  "ok": False,
1617
1910
  "summary": "Codex startup probe timed out.",
1618
1911
  "warnings": base_warnings,
1619
1912
  "errors": [
1620
1913
  "Codex did not answer the startup hello probe within 90 seconds.",
1621
- *self._codex_probe_failure_guidance(config)[0],
1914
+ *failure_errors,
1622
1915
  ],
1623
1916
  "details": details,
1624
1917
  "guidance": [
1625
- *self._codex_probe_failure_guidance(config)[1],
1918
+ *failure_guidance,
1626
1919
  "If `codex` is missing on PATH, install it explicitly with `npm install -g @openai/codex`.",
1627
1920
  "Confirm the configured model is available to your Codex setup. DeepScientist currently probes Codex with the configured runner model first.",
1628
1921
  ],
@@ -1702,9 +1995,19 @@ Use **Test** when the file exposes runtime dependencies.
1702
1995
  warnings.append("Codex returned stderr during the startup probe.")
1703
1996
  if details.get("model_fallback_attempted") and not details.get("model_fallback_used"):
1704
1997
  warnings.append("DeepScientist also tried the current Codex default model, but that fallback probe did not succeed.")
1705
- errors.extend(self._codex_probe_failure_guidance(config)[0])
1998
+ errors.extend(
1999
+ self._codex_probe_failure_guidance(
2000
+ config,
2001
+ stdout_text=stdout_text,
2002
+ stderr_text=stderr_text,
2003
+ )[0]
2004
+ )
1706
2005
  missing_env_key = missing_provider_env_key_from_text(stdout_text, stderr_text) or configured_provider_env_key
1707
- failure_guidance = self._codex_probe_failure_guidance(config)[1]
2006
+ failure_guidance = self._codex_probe_failure_guidance(
2007
+ config,
2008
+ stdout_text=stdout_text,
2009
+ stderr_text=stderr_text,
2010
+ )[1]
1708
2011
  if not ok and missing_env_key and profile:
1709
2012
  errors.append(
1710
2013
  f"Codex profile `{profile}` requires environment variable `{missing_env_key}`, but DeepScientist did not receive it."
@@ -1726,38 +2029,402 @@ Use **Test** when the file exposes runtime dependencies.
1726
2029
  "guidance": [] if ok else failure_guidance,
1727
2030
  }
1728
2031
 
1729
- def _persist_codex_bootstrap_result(self, result: dict) -> None:
2032
+ def _persist_runner_bootstrap_result(self, runner_name: str, result: dict) -> None:
2033
+ normalized_runner = str(runner_name or "codex").strip().lower() or "codex"
1730
2034
  config = self.load_named_normalized("config")
1731
2035
  bootstrap = config.get("bootstrap") if isinstance(config.get("bootstrap"), dict) else {}
1732
2036
  details = result.get("details") if isinstance(result.get("details"), dict) else {}
1733
- bootstrap["codex_ready"] = bool(result.get("ok"))
1734
- bootstrap["codex_last_checked_at"] = details.get("checked_at") or utc_now()
1735
- bootstrap["codex_last_result"] = {
1736
- "ok": bool(result.get("ok")),
1737
- "summary": result.get("summary"),
1738
- "warnings": list(result.get("warnings") or []),
1739
- "errors": list(result.get("errors") or []),
1740
- "guidance": list(result.get("guidance") or []),
1741
- "binary": details.get("binary"),
1742
- "resolved_binary": details.get("resolved_binary"),
1743
- "profile": details.get("profile"),
1744
- "model": details.get("model"),
1745
- "requested_model": details.get("requested_model"),
1746
- "effective_model": details.get("effective_model"),
1747
- "model_fallback_attempted": bool(details.get("model_fallback_attempted")),
1748
- "model_fallback_used": bool(details.get("model_fallback_used")),
1749
- "approval_policy": details.get("approval_policy"),
1750
- "sandbox_mode": details.get("sandbox_mode"),
1751
- "reasoning_effort": details.get("reasoning_effort"),
1752
- "exit_code": details.get("exit_code"),
1753
- "stdout_excerpt": details.get("stdout_excerpt"),
1754
- "stderr_excerpt": details.get("stderr_excerpt"),
2037
+ runner_readiness = bootstrap.get("runner_readiness") if isinstance(bootstrap.get("runner_readiness"), dict) else {}
2038
+ runner_readiness[normalized_runner] = {
2039
+ "ready": bool(result.get("ok")),
2040
+ "last_checked_at": details.get("checked_at") or utc_now(),
2041
+ "last_result": {
2042
+ "ok": bool(result.get("ok")),
2043
+ "summary": result.get("summary"),
2044
+ "warnings": list(result.get("warnings") or []),
2045
+ "errors": list(result.get("errors") or []),
2046
+ "guidance": list(result.get("guidance") or []),
2047
+ "binary": details.get("binary"),
2048
+ "resolved_binary": details.get("resolved_binary"),
2049
+ "model": details.get("model"),
2050
+ "requested_model": details.get("requested_model"),
2051
+ "effective_model": details.get("effective_model"),
2052
+ "exit_code": details.get("exit_code"),
2053
+ "stdout_excerpt": details.get("stdout_excerpt"),
2054
+ "stderr_excerpt": details.get("stderr_excerpt"),
2055
+ "profile": details.get("profile"),
2056
+ "permission_mode": details.get("permission_mode"),
2057
+ "variant": details.get("variant"),
2058
+ },
1755
2059
  }
2060
+ bootstrap["runner_readiness"] = runner_readiness
2061
+ if normalized_runner == "codex":
2062
+ codex_state = runner_readiness["codex"]
2063
+ bootstrap["codex_ready"] = bool(codex_state.get("ready"))
2064
+ bootstrap["codex_last_checked_at"] = codex_state.get("last_checked_at")
2065
+ bootstrap["codex_last_result"] = codex_state.get("last_result")
1756
2066
  config["bootstrap"] = bootstrap
1757
2067
  self.save_named_payload("config", config)
1758
- if bool(result.get("ok")) and bool(details.get("model_fallback_used")):
2068
+ if normalized_runner == "codex" and bool(result.get("ok")) and bool(details.get("model_fallback_used")):
1759
2069
  self._persist_codex_model_inherit(details.get("requested_model"))
1760
2070
 
2071
+ def _persist_codex_bootstrap_result(self, result: dict) -> None:
2072
+ self._persist_runner_bootstrap_result("codex", result)
2073
+
2074
+ @staticmethod
2075
+ def _copy_runner_file_if_exists(source: Path, target: Path) -> None:
2076
+ if not source.exists() or not source.is_file():
2077
+ return
2078
+ target.parent.mkdir(parents=True, exist_ok=True)
2079
+ shutil.copy2(source, target)
2080
+
2081
+ @staticmethod
2082
+ def _claude_auth_runner_env(env: dict[str, str]) -> dict[str, str]:
2083
+ resolved = dict(env)
2084
+ auth_token = str(resolved.get("ANTHROPIC_AUTH_TOKEN") or "").strip()
2085
+ api_key = str(resolved.get("ANTHROPIC_API_KEY") or "").strip()
2086
+ if auth_token and not api_key:
2087
+ resolved["ANTHROPIC_API_KEY"] = auth_token
2088
+ return resolved
2089
+
2090
+ def _runner_missing_binary_guidance(self, runner_name: str, config: dict) -> list[str]:
2091
+ normalized_runner = str(runner_name or "").strip().lower()
2092
+ binary = str(config.get("binary") or normalized_runner).strip() or normalized_runner
2093
+ if normalized_runner == "codex":
2094
+ return self._codex_missing_binary_guidance(config)
2095
+ if normalized_runner == "claude":
2096
+ return [
2097
+ f"Install Claude Code and make sure `{binary} --version` works in the current shell.",
2098
+ "If Claude Code is already installed elsewhere, set `runners.claude.binary` to the absolute path.",
2099
+ ]
2100
+ if normalized_runner == "opencode":
2101
+ return [
2102
+ f"Install OpenCode and make sure `{binary} --version` works in the current shell.",
2103
+ "If OpenCode is already installed elsewhere, set `runners.opencode.binary` to the absolute path.",
2104
+ ]
2105
+ if normalized_runner == "kimi":
2106
+ return [
2107
+ f"Install Kimi Code and make sure `{binary} --version` works in the current shell.",
2108
+ "Run `kimi login` (or just `kimi`) once to complete the first-run login flow.",
2109
+ "If Kimi Code uses a custom home, point `runners.kimi.config_dir` at the correct `~/.kimi`-style directory that contains `config.toml` and `mcp.json`.",
2110
+ ]
2111
+ return [f"Install runner `{normalized_runner}` and ensure `{binary}` is on PATH."]
2112
+
2113
+ def _probe_claude_runner(self, config: dict) -> dict:
2114
+ checked_at = utc_now()
2115
+ binary = str(config.get("binary") or "claude").strip() or "claude"
2116
+ resolved_binary = resolve_runner_binary(binary, runner_name="claude")
2117
+ requested_model = str(config.get("model") or "inherit").strip() or "inherit"
2118
+ permission_mode = str(config.get("permission_mode") or "bypassPermissions").strip() or "bypassPermissions"
2119
+ details: dict[str, object] = {
2120
+ "binary": binary,
2121
+ "resolved_binary": resolved_binary,
2122
+ "config_dir": str(config.get("config_dir") or "~/.claude"),
2123
+ "model": requested_model,
2124
+ "requested_model": requested_model,
2125
+ "effective_model": requested_model,
2126
+ "permission_mode": permission_mode,
2127
+ "checked_at": checked_at,
2128
+ }
2129
+ if not resolved_binary:
2130
+ return {
2131
+ "ok": False,
2132
+ "summary": "Claude Code startup probe failed before execution.",
2133
+ "warnings": [],
2134
+ "errors": [f"Claude Code binary `{binary}` is not available."],
2135
+ "details": details,
2136
+ "guidance": self._runner_missing_binary_guidance("claude", config),
2137
+ }
2138
+ env = ensure_utf8_subprocess_env(os.environ.copy())
2139
+ env.update(self._claude_auth_runner_env(self._codex_runner_env(config)))
2140
+ temp_home_handle = tempfile.TemporaryDirectory()
2141
+ try:
2142
+ temp_home = Path(temp_home_handle.name)
2143
+ source_home = Path(str(config.get("config_dir") or Path.home() / ".claude")).expanduser()
2144
+ for filename in (".credentials.json", "settings.json", "settings.local.json"):
2145
+ self._copy_runner_file_if_exists(source_home / filename, temp_home / filename)
2146
+ env["CLAUDE_CONFIG_DIR"] = str(temp_home)
2147
+ command = [
2148
+ resolved_binary,
2149
+ "-p",
2150
+ "--input-format",
2151
+ "text",
2152
+ "--output-format",
2153
+ "json",
2154
+ "--add-dir",
2155
+ str(repo_root()),
2156
+ "--no-session-persistence",
2157
+ "--permission-mode",
2158
+ permission_mode,
2159
+ ]
2160
+ if requested_model.lower() not in {"", "inherit", "default", "claude-default"}:
2161
+ command.extend(["--model", requested_model])
2162
+ command.extend(["--tools", ""])
2163
+ result = subprocess.run(
2164
+ command,
2165
+ input="Reply with exactly HELLO.",
2166
+ cwd=str(repo_root()),
2167
+ env=env,
2168
+ capture_output=True,
2169
+ timeout=90,
2170
+ check=False,
2171
+ **utf8_text_subprocess_kwargs(),
2172
+ )
2173
+ except subprocess.TimeoutExpired as exc:
2174
+ details.update({
2175
+ "exit_code": None,
2176
+ "stdout_excerpt": self._compact_probe_text(exc.stdout or ""),
2177
+ "stderr_excerpt": self._compact_probe_text(exc.stderr or ""),
2178
+ })
2179
+ return {
2180
+ "ok": False,
2181
+ "summary": "Claude Code startup probe timed out.",
2182
+ "warnings": [],
2183
+ "errors": ["Claude Code did not answer the startup probe within 90 seconds."],
2184
+ "details": details,
2185
+ "guidance": [
2186
+ "Run a small headless Claude Code request manually and confirm it can answer before starting DeepScientist.",
2187
+ ],
2188
+ }
2189
+ finally:
2190
+ temp_home_handle.cleanup()
2191
+ stdout_text = (result.stdout or "").strip()
2192
+ stderr_text = (result.stderr or "").strip()
2193
+ ok = result.returncode == 0 and "HELLO" in f"{stdout_text}\n{stderr_text}".upper()
2194
+ details.update({
2195
+ "exit_code": result.returncode,
2196
+ "stdout_excerpt": self._compact_probe_text(stdout_text),
2197
+ "stderr_excerpt": self._compact_probe_text(stderr_text),
2198
+ "probe_command": command,
2199
+ })
2200
+ return {
2201
+ "ok": ok,
2202
+ "summary": "Claude Code startup probe completed." if ok else "Claude Code startup probe failed.",
2203
+ "warnings": ["Claude Code returned stderr during the startup probe."] if stderr_text else [],
2204
+ "errors": [] if ok else ["Claude Code did not complete the startup hello probe successfully."],
2205
+ "details": details,
2206
+ "guidance": [] if ok else [
2207
+ "Run `claude -p \"Reply with exactly HELLO.\" --output-format json --tools \"\"` manually and confirm it returns `HELLO`.",
2208
+ "If Claude Code uses a custom account or credential path, point `runners.claude.config_dir` at the correct home.",
2209
+ ],
2210
+ }
2211
+
2212
+ def _probe_opencode_runner(self, config: dict) -> dict:
2213
+ checked_at = utc_now()
2214
+ binary = str(config.get("binary") or "opencode").strip() or "opencode"
2215
+ resolved_binary = resolve_runner_binary(binary, runner_name="opencode")
2216
+ requested_model = str(config.get("model") or "inherit").strip() or "inherit"
2217
+ variant = str(config.get("variant") or "").strip() or None
2218
+ permission_mode = str(config.get("permission_mode") or "allow").strip().lower() or "allow"
2219
+ details: dict[str, object] = {
2220
+ "binary": binary,
2221
+ "resolved_binary": resolved_binary,
2222
+ "config_dir": str(config.get("config_dir") or "~/.config/opencode"),
2223
+ "model": requested_model,
2224
+ "requested_model": requested_model,
2225
+ "effective_model": requested_model,
2226
+ "variant": variant,
2227
+ "permission_mode": permission_mode,
2228
+ "checked_at": checked_at,
2229
+ }
2230
+ if not resolved_binary:
2231
+ return {
2232
+ "ok": False,
2233
+ "summary": "OpenCode startup probe failed before execution.",
2234
+ "warnings": [],
2235
+ "errors": [f"OpenCode binary `{binary}` is not available."],
2236
+ "details": details,
2237
+ "guidance": self._runner_missing_binary_guidance("opencode", config),
2238
+ }
2239
+ env = ensure_utf8_subprocess_env(os.environ.copy())
2240
+ env.update(self._codex_runner_env(config))
2241
+ temp_home_handle = tempfile.TemporaryDirectory()
2242
+ try:
2243
+ temp_home = Path(temp_home_handle.name)
2244
+ config_root = temp_home / ".config" / "opencode"
2245
+ config_root.mkdir(parents=True, exist_ok=True)
2246
+ source_root = Path(str(config.get("config_dir") or Path.home() / ".config" / "opencode")).expanduser()
2247
+ self._copy_runner_file_if_exists(source_root / "opencode.json", config_root / "opencode.json")
2248
+ env["HOME"] = str(temp_home)
2249
+ env["XDG_CONFIG_HOME"] = str(temp_home / ".config")
2250
+ command = [
2251
+ resolved_binary,
2252
+ "run",
2253
+ "--format",
2254
+ "json",
2255
+ "--pure",
2256
+ "--dir",
2257
+ str(repo_root()),
2258
+ ]
2259
+ if requested_model.lower() not in {"", "inherit", "default", "opencode-default"}:
2260
+ command.extend(["--model", requested_model])
2261
+ if variant:
2262
+ command.extend(["--variant", variant])
2263
+ command.append("Reply with exactly HELLO")
2264
+ result = subprocess.run(
2265
+ command,
2266
+ cwd=str(repo_root()),
2267
+ env=env,
2268
+ capture_output=True,
2269
+ timeout=90,
2270
+ check=False,
2271
+ **utf8_text_subprocess_kwargs(),
2272
+ )
2273
+ except subprocess.TimeoutExpired as exc:
2274
+ details.update({
2275
+ "exit_code": None,
2276
+ "stdout_excerpt": self._compact_probe_text(exc.stdout or ""),
2277
+ "stderr_excerpt": self._compact_probe_text(exc.stderr or ""),
2278
+ })
2279
+ return {
2280
+ "ok": False,
2281
+ "summary": "OpenCode startup probe timed out.",
2282
+ "warnings": [],
2283
+ "errors": ["OpenCode did not answer the startup probe within 90 seconds."],
2284
+ "details": details,
2285
+ "guidance": [
2286
+ "Run a small `opencode run --format json` request manually and confirm it can answer before starting DeepScientist.",
2287
+ ],
2288
+ }
2289
+ finally:
2290
+ temp_home_handle.cleanup()
2291
+ stdout_text = (result.stdout or "").strip()
2292
+ stderr_text = (result.stderr or "").strip()
2293
+ ok = result.returncode == 0 and "HELLO" in f"{stdout_text}\n{stderr_text}".upper()
2294
+ details.update({
2295
+ "exit_code": result.returncode,
2296
+ "stdout_excerpt": self._compact_probe_text(stdout_text),
2297
+ "stderr_excerpt": self._compact_probe_text(stderr_text),
2298
+ "probe_command": command,
2299
+ })
2300
+ return {
2301
+ "ok": ok,
2302
+ "summary": "OpenCode startup probe completed." if ok else "OpenCode startup probe failed.",
2303
+ "warnings": ["OpenCode returned stderr during the startup probe."] if stderr_text else [],
2304
+ "errors": [] if ok else ["OpenCode did not complete the startup hello probe successfully."],
2305
+ "details": details,
2306
+ "guidance": [] if ok else [
2307
+ "Run `opencode run --format json \"Reply with exactly HELLO\"` manually and confirm it succeeds.",
2308
+ "If OpenCode uses a custom config root, point `runners.opencode.config_dir` at the correct directory.",
2309
+ ],
2310
+ }
2311
+
2312
+ def _probe_kimi_runner(self, config: dict) -> dict:
2313
+ checked_at = utc_now()
2314
+ binary = str(config.get("binary") or "kimi").strip() or "kimi"
2315
+ resolved_binary = resolve_runner_binary(binary, runner_name="kimi")
2316
+ requested_model = str(config.get("model") or "inherit").strip() or "inherit"
2317
+ agent_name = str(config.get("agent") or "").strip() or None
2318
+ yolo_enabled = bool(config.get("yolo", True))
2319
+ thinking_enabled = bool(config.get("thinking", False))
2320
+ details: dict[str, object] = {
2321
+ "binary": binary,
2322
+ "resolved_binary": resolved_binary,
2323
+ "config_dir": str(config.get("config_dir") or "~/.kimi"),
2324
+ "model": requested_model,
2325
+ "requested_model": requested_model,
2326
+ "effective_model": requested_model,
2327
+ "agent": agent_name,
2328
+ "thinking": thinking_enabled,
2329
+ "yolo": yolo_enabled,
2330
+ "checked_at": checked_at,
2331
+ }
2332
+ if not resolved_binary:
2333
+ return {
2334
+ "ok": False,
2335
+ "summary": "Kimi Code startup probe failed before execution.",
2336
+ "warnings": [],
2337
+ "errors": [f"Kimi Code binary `{binary}` is not available."],
2338
+ "details": details,
2339
+ "guidance": self._runner_missing_binary_guidance("kimi", config),
2340
+ }
2341
+ env = ensure_utf8_subprocess_env(os.environ.copy())
2342
+ env.update(self._codex_runner_env(config))
2343
+ temp_home_handle = tempfile.TemporaryDirectory()
2344
+ try:
2345
+ temp_home = Path(temp_home_handle.name)
2346
+ kimi_home = materialize_kimi_runtime_home(
2347
+ source_home=Path(str(config.get("config_dir") or Path.home() / ".kimi")).expanduser(),
2348
+ target_home=temp_home,
2349
+ )
2350
+ mcp_config_path = kimi_home / "mcp.json"
2351
+ write_json(mcp_config_path, {"mcpServers": {}})
2352
+ env["HOME"] = str(temp_home)
2353
+ env["USERPROFILE"] = str(temp_home)
2354
+ command = [
2355
+ resolved_binary,
2356
+ "--print",
2357
+ "--input-format",
2358
+ "text",
2359
+ "--output-format",
2360
+ "stream-json",
2361
+ "--work-dir",
2362
+ str(repo_root()),
2363
+ "--mcp-config-file",
2364
+ str(mcp_config_path),
2365
+ ]
2366
+ if yolo_enabled:
2367
+ command.append("--yolo")
2368
+ if requested_model.lower() not in {"", "inherit", "default", "kimi-default"}:
2369
+ command.extend(["--model", requested_model])
2370
+ if agent_name:
2371
+ command.extend(["--agent", agent_name])
2372
+ if thinking_enabled:
2373
+ command.append("--thinking")
2374
+ result = subprocess.run(
2375
+ command,
2376
+ input="Reply with exactly HELLO.",
2377
+ cwd=str(repo_root()),
2378
+ env=env,
2379
+ capture_output=True,
2380
+ timeout=90,
2381
+ check=False,
2382
+ **utf8_text_subprocess_kwargs(),
2383
+ )
2384
+ except subprocess.TimeoutExpired as exc:
2385
+ details.update(
2386
+ {
2387
+ "exit_code": None,
2388
+ "stdout_excerpt": self._compact_probe_text(exc.stdout or ""),
2389
+ "stderr_excerpt": self._compact_probe_text(exc.stderr or ""),
2390
+ }
2391
+ )
2392
+ return {
2393
+ "ok": False,
2394
+ "summary": "Kimi Code startup probe timed out.",
2395
+ "warnings": [],
2396
+ "errors": ["Kimi Code did not answer the startup probe within 90 seconds."],
2397
+ "details": details,
2398
+ "guidance": [
2399
+ "Run a small `kimi --print --output-format stream-json` request manually and confirm it can answer before starting DeepScientist.",
2400
+ ],
2401
+ }
2402
+ finally:
2403
+ temp_home_handle.cleanup()
2404
+ stdout_text = (result.stdout or "").strip()
2405
+ stderr_text = (result.stderr or "").strip()
2406
+ ok = result.returncode == 0 and "HELLO" in f"{stdout_text}\n{stderr_text}".upper()
2407
+ details.update(
2408
+ {
2409
+ "exit_code": result.returncode,
2410
+ "stdout_excerpt": self._compact_probe_text(stdout_text),
2411
+ "stderr_excerpt": self._compact_probe_text(stderr_text),
2412
+ "probe_command": command,
2413
+ }
2414
+ )
2415
+ return {
2416
+ "ok": ok,
2417
+ "summary": "Kimi Code startup probe completed." if ok else "Kimi Code startup probe failed.",
2418
+ "warnings": ["Kimi Code returned stderr during the startup probe."] if stderr_text else [],
2419
+ "errors": [] if ok else ["Kimi Code did not complete the startup hello probe successfully."],
2420
+ "details": details,
2421
+ "guidance": [] if ok else [
2422
+ "Run `kimi --print --input-format text --output-format stream-json --yolo` manually and confirm it returns `HELLO`.",
2423
+ "Run `kimi login` first if this machine has not completed the Kimi Code login flow yet.",
2424
+ "If Kimi Code uses a custom home, point `runners.kimi.config_dir` at the correct `~/.kimi`-style directory.",
2425
+ ],
2426
+ }
2427
+
1761
2428
  @staticmethod
1762
2429
  def _compact_probe_text(value: str, *, limit: int = 1200) -> str:
1763
2430
  text = str(value or "").strip()
@@ -2012,11 +2679,31 @@ Use **Test** when the file exposes runtime dependencies.
2012
2679
  defaults = default_payload(name, self.home)
2013
2680
  if name == "runners":
2014
2681
  normalized = self._deep_merge(defaults, prepared)
2682
+ runtime_enabled_runners = self._runtime_enabled_runner_names()
2015
2683
  codex = normalized.get("codex")
2016
- if isinstance(codex, dict) and self._looks_like_legacy_codex_retry_profile(codex):
2017
- codex["retry_initial_backoff_sec"] = 10.0
2018
- codex["retry_backoff_multiplier"] = 6.0
2019
- codex["retry_max_backoff_sec"] = 1800.0
2684
+ if isinstance(codex, dict):
2685
+ if self._looks_like_legacy_codex_retry_profile(codex):
2686
+ codex["retry_initial_backoff_sec"] = 10.0
2687
+ codex["retry_backoff_multiplier"] = 6.0
2688
+ codex["retry_max_backoff_sec"] = 1800.0
2689
+ if self._looks_like_preupgrade_codex_retry_attempt_profile(codex):
2690
+ codex["retry_max_attempts"] = 7
2691
+ claude = normalized.get("claude")
2692
+ if isinstance(claude, dict):
2693
+ legacy_approval_policy = str(claude.get("approval_policy") or "").strip().lower()
2694
+ if legacy_approval_policy and not str(claude.get("permission_mode") or "").strip():
2695
+ if legacy_approval_policy == "never":
2696
+ claude["permission_mode"] = "bypassPermissions"
2697
+ elif legacy_approval_policy in {"on-request", "default"}:
2698
+ claude["permission_mode"] = "default"
2699
+ if "approval_policy" in claude:
2700
+ claude.pop("approval_policy", None)
2701
+ if "sandbox_mode" in claude:
2702
+ claude.pop("sandbox_mode", None)
2703
+ for runner_name in runtime_enabled_runners:
2704
+ runner_config = normalized.get(runner_name)
2705
+ if isinstance(runner_config, dict):
2706
+ runner_config["enabled"] = True
2020
2707
  return normalized
2021
2708
  if name == "connectors":
2022
2709
  normalized = deepcopy(defaults)
@@ -2061,9 +2748,44 @@ Use **Test** when the file exposes runtime dependencies.
2061
2748
  return normalized
2062
2749
  return self._deep_merge(defaults, prepared)
2063
2750
 
2751
+ @staticmethod
2752
+ def _normalize_runtime_runner_name(value: object) -> str:
2753
+ normalized = str(value or "").strip().lower().replace("_", "-")
2754
+ if normalized in {"claude-code", "claudecode"}:
2755
+ return "claude"
2756
+ if normalized in {"kimi-code", "kimicode"}:
2757
+ return "kimi"
2758
+ if normalized in {"open-code", "open code", "opencode-ai", "opencodeai"}:
2759
+ return "opencode"
2760
+ return normalized.replace("-", "")
2761
+
2762
+ @classmethod
2763
+ def _runtime_enabled_runner_names(cls) -> set[str]:
2764
+ names: set[str] = set()
2765
+ raw_values = [
2766
+ os.environ.get("DEEPSCIENTIST_DEFAULT_RUNNER"),
2767
+ os.environ.get("DS_DEFAULT_RUNNER"),
2768
+ os.environ.get("DEEPSCIENTIST_ENABLE_RUNNER"),
2769
+ os.environ.get("DS_ENABLE_RUNNER"),
2770
+ os.environ.get("DEEPSCIENTIST_ENABLE_RUNNERS"),
2771
+ os.environ.get("DS_ENABLE_RUNNERS"),
2772
+ ]
2773
+ for raw_value in raw_values:
2774
+ for item in str(raw_value or "").replace(";", ",").split(","):
2775
+ normalized = cls._normalize_runtime_runner_name(item)
2776
+ if normalized:
2777
+ names.add(normalized)
2778
+ return names
2779
+
2064
2780
  def _normalize_config_payload(self, payload: dict) -> dict:
2065
2781
  defaults = default_payload("config", self.home)
2066
2782
  normalized = self._deep_merge(defaults, payload)
2783
+ default_runner_override = str(
2784
+ os.environ.get("DEEPSCIENTIST_DEFAULT_RUNNER") or os.environ.get("DS_DEFAULT_RUNNER") or ""
2785
+ ).strip().lower()
2786
+ default_runner_override = self._normalize_runtime_runner_name(default_runner_override)
2787
+ if default_runner_override:
2788
+ normalized["default_runner"] = default_runner_override
2067
2789
  bootstrap = normalized.get("bootstrap") if isinstance(normalized.get("bootstrap"), dict) else {}
2068
2790
  raw_bootstrap = payload.get("bootstrap") if isinstance(payload.get("bootstrap"), dict) else {}
2069
2791
  connectors = normalized.get("connectors") if isinstance(normalized.get("connectors"), dict) else {}
@@ -2090,6 +2812,25 @@ Use **Test** when the file exposes runtime dependencies.
2090
2812
  bootstrap["locale_initialized_from_browser"] = locale_initialized_from_browser
2091
2813
  bootstrap["locale_initialized_at"] = bootstrap.get("locale_initialized_at")
2092
2814
  bootstrap["locale_initialized_browser_locale"] = bootstrap.get("locale_initialized_browser_locale")
2815
+ runner_readiness = bootstrap.get("runner_readiness") if isinstance(bootstrap.get("runner_readiness"), dict) else {}
2816
+ normalized_runner_readiness: dict[str, dict[str, Any]] = {}
2817
+ for runner_name in list_builtin_runner_names():
2818
+ state = runner_readiness.get(runner_name) if isinstance(runner_readiness.get(runner_name), dict) else {}
2819
+ if runner_name == "codex" and not state:
2820
+ state = {
2821
+ "ready": bool(bootstrap.get("codex_ready", False)),
2822
+ "last_checked_at": bootstrap.get("codex_last_checked_at"),
2823
+ "last_result": bootstrap.get("codex_last_result") if isinstance(bootstrap.get("codex_last_result"), dict) else {},
2824
+ }
2825
+ normalized_runner_readiness[runner_name] = {
2826
+ "ready": bool(state.get("ready", False)),
2827
+ "last_checked_at": state.get("last_checked_at"),
2828
+ "last_result": state.get("last_result") if isinstance(state.get("last_result"), dict) else {},
2829
+ }
2830
+ bootstrap["runner_readiness"] = normalized_runner_readiness
2831
+ bootstrap["codex_ready"] = bool(normalized_runner_readiness.get("codex", {}).get("ready", False))
2832
+ bootstrap["codex_last_checked_at"] = normalized_runner_readiness.get("codex", {}).get("last_checked_at")
2833
+ bootstrap["codex_last_result"] = normalized_runner_readiness.get("codex", {}).get("last_result") if isinstance(normalized_runner_readiness.get("codex", {}).get("last_result"), dict) else {}
2093
2834
  normalized["bootstrap"] = bootstrap
2094
2835
  raw_system_enabled = raw_connectors.get("system_enabled") if isinstance(raw_connectors.get("system_enabled"), dict) else {}
2095
2836
  default_system_enabled = (
@@ -2110,6 +2851,85 @@ Use **Test** when the file exposes runtime dependencies.
2110
2851
  for name in SYSTEM_CONNECTOR_NAMES
2111
2852
  }
2112
2853
  normalized["connectors"] = connectors
2854
+ hardware = normalized.get("hardware") if isinstance(normalized.get("hardware"), dict) else {}
2855
+ raw_hardware = payload.get("hardware") if isinstance(payload.get("hardware"), dict) else {}
2856
+ gpu_selection_mode = str(raw_hardware.get("gpu_selection_mode") or hardware.get("gpu_selection_mode") or "all").strip().lower()
2857
+ if gpu_selection_mode not in {"all", "selected"}:
2858
+ gpu_selection_mode = "all"
2859
+ raw_selected_gpu_ids = raw_hardware.get("selected_gpu_ids", hardware.get("selected_gpu_ids", []))
2860
+ selected_gpu_ids: list[str] = []
2861
+ if isinstance(raw_selected_gpu_ids, list):
2862
+ for item in raw_selected_gpu_ids:
2863
+ normalized_id = str(item or "").strip()
2864
+ if normalized_id and normalized_id not in selected_gpu_ids:
2865
+ selected_gpu_ids.append(normalized_id)
2866
+ elif isinstance(raw_selected_gpu_ids, str):
2867
+ for item in raw_selected_gpu_ids.split(","):
2868
+ normalized_id = item.strip()
2869
+ if normalized_id and normalized_id not in selected_gpu_ids:
2870
+ selected_gpu_ids.append(normalized_id)
2871
+ hardware["gpu_selection_mode"] = gpu_selection_mode
2872
+ hardware["selected_gpu_ids"] = selected_gpu_ids
2873
+ hardware["include_system_hardware_in_prompt"] = self._coerce_bool(
2874
+ raw_hardware.get(
2875
+ "include_system_hardware_in_prompt",
2876
+ hardware.get("include_system_hardware_in_prompt", True),
2877
+ ),
2878
+ default=True,
2879
+ )
2880
+ normalized["hardware"] = hardware
2881
+ memory = normalized.get("memory") if isinstance(normalized.get("memory"), dict) else {}
2882
+ raw_memory = payload.get("memory") if isinstance(payload.get("memory"), dict) else {}
2883
+ read_visibility_mode = str(
2884
+ raw_memory.get("read_visibility_mode", memory.get("read_visibility_mode", "independent")) or "independent"
2885
+ ).strip().lower()
2886
+ if read_visibility_mode not in {"independent", "shared_across_quests"}:
2887
+ read_visibility_mode = "independent"
2888
+ memory["read_visibility_mode"] = read_visibility_mode
2889
+ normalized["memory"] = memory
2890
+ literature = normalized.get("literature") if isinstance(normalized.get("literature"), dict) else {}
2891
+ raw_literature = payload.get("literature") if isinstance(payload.get("literature"), dict) else {}
2892
+ default_literature = defaults.get("literature") if isinstance(defaults.get("literature"), dict) else {}
2893
+ deepxiv_defaults = default_literature.get("deepxiv") if isinstance(default_literature.get("deepxiv"), dict) else {}
2894
+ deepxiv = literature.get("deepxiv") if isinstance(literature.get("deepxiv"), dict) else {}
2895
+ raw_deepxiv = raw_literature.get("deepxiv") if isinstance(raw_literature.get("deepxiv"), dict) else {}
2896
+ deepxiv["enabled"] = self._coerce_bool(
2897
+ raw_deepxiv.get("enabled", deepxiv.get("enabled", deepxiv_defaults.get("enabled", False))),
2898
+ default=bool(deepxiv_defaults.get("enabled", False)),
2899
+ )
2900
+ deepxiv["base_url"] = str(
2901
+ raw_deepxiv.get("base_url", deepxiv.get("base_url", deepxiv_defaults.get("base_url", "https://data.rag.ac.cn"))) or ""
2902
+ ).strip() or str(deepxiv_defaults.get("base_url") or "https://data.rag.ac.cn")
2903
+ deepxiv["token"] = str(raw_deepxiv.get("token", deepxiv.get("token", "")) or "").strip() or None
2904
+ deepxiv["token_env"] = str(
2905
+ raw_deepxiv.get("token_env", deepxiv.get("token_env", deepxiv_defaults.get("token_env", "DEEPXIV_TOKEN"))) or ""
2906
+ ).strip() or None
2907
+ try:
2908
+ raw_result_size = raw_deepxiv.get(
2909
+ "default_result_size",
2910
+ deepxiv.get("default_result_size", deepxiv_defaults.get("default_result_size", 10)),
2911
+ )
2912
+ deepxiv["default_result_size"] = max(1, int(raw_result_size))
2913
+ except (TypeError, ValueError):
2914
+ deepxiv["default_result_size"] = int(deepxiv_defaults.get("default_result_size", 10) or 10)
2915
+ try:
2916
+ raw_preview_characters = raw_deepxiv.get(
2917
+ "preview_characters",
2918
+ deepxiv.get("preview_characters", deepxiv_defaults.get("preview_characters", 1200)),
2919
+ )
2920
+ deepxiv["preview_characters"] = max(200, int(raw_preview_characters))
2921
+ except (TypeError, ValueError):
2922
+ deepxiv["preview_characters"] = int(deepxiv_defaults.get("preview_characters", 1200) or 1200)
2923
+ try:
2924
+ raw_timeout = raw_deepxiv.get(
2925
+ "request_timeout_seconds",
2926
+ deepxiv.get("request_timeout_seconds", deepxiv_defaults.get("request_timeout_seconds", 20)),
2927
+ )
2928
+ deepxiv["request_timeout_seconds"] = max(3, int(raw_timeout))
2929
+ except (TypeError, ValueError):
2930
+ deepxiv["request_timeout_seconds"] = int(deepxiv_defaults.get("request_timeout_seconds", 20) or 20)
2931
+ literature["deepxiv"] = deepxiv
2932
+ normalized["literature"] = literature
2113
2933
  return normalized
2114
2934
 
2115
2935
  @staticmethod
@@ -2122,6 +2942,22 @@ Use **Test** when the file exposes runtime dependencies.
2122
2942
  return False
2123
2943
  return abs(initial - 1.0) < 1e-9 and abs(multiplier - 2.0) < 1e-9 and abs(max_backoff - 8.0) < 1e-9
2124
2944
 
2945
+ @staticmethod
2946
+ def _looks_like_preupgrade_codex_retry_attempt_profile(payload: dict) -> bool:
2947
+ try:
2948
+ max_attempts = int(payload.get("retry_max_attempts"))
2949
+ initial = float(payload.get("retry_initial_backoff_sec"))
2950
+ multiplier = float(payload.get("retry_backoff_multiplier"))
2951
+ max_backoff = float(payload.get("retry_max_backoff_sec"))
2952
+ except (TypeError, ValueError):
2953
+ return False
2954
+ return (
2955
+ max_attempts == 5
2956
+ and abs(initial - 10.0) < 1e-9
2957
+ and abs(multiplier - 6.0) < 1e-9
2958
+ and abs(max_backoff - 1800.0) < 1e-9
2959
+ )
2960
+
2125
2961
  @staticmethod
2126
2962
  def _coerce_bool(value: object, *, default: bool = False) -> bool:
2127
2963
  if value is None: