@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
@@ -22,6 +22,32 @@ _COPILOT_LEAD_MESSAGE = (
22
22
  "你可以让我读论文、改代码、看实验、整理思路,或者直接开始执行一个任务。"
23
23
  )
24
24
 
25
+ _STATIC_MIME_OVERRIDES = {
26
+ ".js": "text/javascript",
27
+ ".mjs": "text/javascript",
28
+ ".cjs": "text/javascript",
29
+ ".css": "text/css",
30
+ ".map": "application/json",
31
+ ".json": "application/json",
32
+ ".wasm": "application/wasm",
33
+ ".svg": "image/svg+xml",
34
+ ".png": "image/png",
35
+ ".jpg": "image/jpeg",
36
+ ".jpeg": "image/jpeg",
37
+ ".gif": "image/gif",
38
+ ".webp": "image/webp",
39
+ ".ico": "image/x-icon",
40
+ ".woff": "font/woff",
41
+ ".woff2": "font/woff2",
42
+ ".ttf": "font/ttf",
43
+ ".otf": "font/otf",
44
+ ".eot": "application/vnd.ms-fontobject",
45
+ ".pdf": "application/pdf",
46
+ ".zip": "application/zip",
47
+ ".txt": "text/plain; charset=utf-8",
48
+ ".md": "text/markdown; charset=utf-8",
49
+ }
50
+
25
51
 
26
52
  class ApiHandlers:
27
53
  def __init__(self, app: "DaemonApp") -> None:
@@ -51,7 +77,7 @@ class ApiHandlers:
51
77
  path = resolve_within(dist_root, ui_path)
52
78
  if not path.exists() or not path.is_file():
53
79
  return 404, {"Content-Type": "text/plain; charset=utf-8"}, b"Not Found"
54
- mime_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
80
+ mime_type = self._guess_static_mime_type(path)
55
81
  return 200, self._asset_headers(mime_type), path.read_bytes()
56
82
 
57
83
  @staticmethod
@@ -68,6 +94,13 @@ class ApiHandlers:
68
94
  "Cache-Control": "no-store, max-age=0, must-revalidate",
69
95
  }
70
96
 
97
+ @staticmethod
98
+ def _guess_static_mime_type(path: Path) -> str:
99
+ extension = path.suffix.lower()
100
+ if extension in _STATIC_MIME_OVERRIDES:
101
+ return _STATIC_MIME_OVERRIDES[extension]
102
+ return mimetypes.guess_type(path.name)[0] or "application/octet-stream"
103
+
71
104
  def _ui_dist_root(self) -> Path | None:
72
105
  dist_root = self.app.repo_root / "src" / "ui" / "dist"
73
106
  if dist_root.exists() and dist_root.joinpath("index.html").exists():
@@ -283,6 +316,396 @@ npm --prefix src/ui run build</pre>
283
316
  }
284
317
  return self.app.request_shutdown(source=source)
285
318
 
319
+ def admin_doctor(self) -> dict:
320
+ cached = self.app.admin_task_service.cached_result("doctor.json")
321
+ latest_task = next(
322
+ (
323
+ item
324
+ for item in self.app.admin_task_service.list_tasks(kind="doctor", limit=10)
325
+ if str(item.get("status") or "").strip().lower() in {"queued", "running"}
326
+ ),
327
+ None,
328
+ )
329
+ return {
330
+ "ok": True,
331
+ "cached": cached,
332
+ "latest_task": latest_task,
333
+ }
334
+
335
+ def admin_overview(self) -> dict:
336
+ return self.app.admin_service.overview()
337
+
338
+ def admin_quests(self, path: str) -> dict:
339
+ query = self.parse_query(path)
340
+ limit_raw = ((query.get("limit") or ["100"])[0] or "100").strip()
341
+ try:
342
+ limit = max(1, min(int(limit_raw), 500))
343
+ except ValueError:
344
+ limit = 100
345
+ return self.app.admin_service.quests(limit=limit)
346
+
347
+ def admin_quest_summary(self, quest_id: str) -> dict | tuple[int, dict]:
348
+ try:
349
+ return self.app.admin_service.quest_summary(quest_id)
350
+ except FileNotFoundError:
351
+ return 404, {"ok": False, "message": f"Unknown quest `{quest_id}`."}
352
+
353
+ def admin_runtime_sessions(self, path: str) -> dict:
354
+ query = self.parse_query(path)
355
+ limit_raw = ((query.get("limit") or ["200"])[0] or "200").strip()
356
+ try:
357
+ limit = max(1, min(int(limit_raw), 1000))
358
+ except ValueError:
359
+ limit = 200
360
+ return self.app.admin_service.runtime_sessions(limit=limit)
361
+
362
+ def admin_log_sources(self) -> dict:
363
+ return self.app.admin_service.log_sources()
364
+
365
+ def admin_log_tail(self, path: str) -> dict | tuple[int, dict]:
366
+ query = self.parse_query(path)
367
+ source = ((query.get("source") or [""])[0] or "").strip()
368
+ if not source:
369
+ return 400, {"ok": False, "message": "`source` is required."}
370
+ line_count_raw = ((query.get("line_count") or ["200"])[0] or "200").strip()
371
+ try:
372
+ line_count = max(1, min(int(line_count_raw), 2000))
373
+ except ValueError:
374
+ line_count = 200
375
+ try:
376
+ return self.app.admin_service.log_tail(source, line_count=line_count)
377
+ except FileNotFoundError as exc:
378
+ return 404, {"ok": False, "message": str(exc)}
379
+
380
+ def admin_failures(self, path: str) -> dict:
381
+ query = self.parse_query(path)
382
+ limit_raw = ((query.get("limit") or ["100"])[0] or "100").strip()
383
+ try:
384
+ limit = max(1, min(int(limit_raw), 500))
385
+ except ValueError:
386
+ limit = 100
387
+ return self.app.admin_service.failures(limit=limit)
388
+
389
+ def admin_errors(self, path: str) -> dict:
390
+ query = self.parse_query(path)
391
+ limit_raw = ((query.get("limit") or ["100"])[0] or "100").strip()
392
+ try:
393
+ limit = max(1, min(int(limit_raw), 500))
394
+ except ValueError:
395
+ limit = 100
396
+ return self.app.admin_service.error_console(limit=limit)
397
+
398
+ def admin_runtime_tools(self) -> dict:
399
+ return self.app.admin_service.runtime_tools()
400
+
401
+ def admin_system_hardware(self) -> dict:
402
+ return self.app.admin_service.system_hardware(refresh=False)
403
+
404
+ def admin_system_hardware_update(self, body: dict | None = None) -> dict | tuple[int, dict]:
405
+ payload = body if isinstance(body, dict) else {}
406
+ selection_mode = payload.get("gpu_selection_mode")
407
+ selected_gpu_ids_raw = payload.get("selected_gpu_ids")
408
+ selected_gpu_ids = (
409
+ [str(item) for item in selected_gpu_ids_raw]
410
+ if isinstance(selected_gpu_ids_raw, list)
411
+ else None
412
+ )
413
+ include_in_prompt_raw = payload.get("include_system_hardware_in_prompt")
414
+ memory_read_visibility_mode = payload.get("memory_read_visibility_mode")
415
+ result = self.app.admin_service.update_system_hardware_preferences(
416
+ gpu_selection_mode=str(selection_mode) if selection_mode is not None else None,
417
+ selected_gpu_ids=selected_gpu_ids,
418
+ include_system_hardware_in_prompt=(
419
+ bool(include_in_prompt_raw) if include_in_prompt_raw is not None else None
420
+ ),
421
+ memory_read_visibility_mode=(
422
+ str(memory_read_visibility_mode) if memory_read_visibility_mode is not None else None
423
+ ),
424
+ )
425
+ self.app.admin_service.write_audit(
426
+ action="system.hardware.update",
427
+ gpu_selection_mode=((result.get("preferences") or {}) if isinstance(result.get("preferences"), dict) else {}).get("gpu_selection_mode"),
428
+ selected_gpu_ids=((result.get("preferences") or {}) if isinstance(result.get("preferences"), dict) else {}).get("selected_gpu_ids"),
429
+ effective_gpu_ids=((result.get("preferences") or {}) if isinstance(result.get("preferences"), dict) else {}).get("effective_gpu_ids"),
430
+ memory_read_visibility_mode=((result.get("memory_preferences") or {}) if isinstance(result.get("memory_preferences"), dict) else {}).get("read_visibility_mode"),
431
+ )
432
+ return result
433
+
434
+ def admin_chart_catalog(self) -> dict:
435
+ return self.app.admin_service.chart_catalog()
436
+
437
+ def admin_chart_query(self, body: dict | None = None) -> dict | tuple[int, dict]:
438
+ payload = body if isinstance(body, dict) else {}
439
+ items = payload.get("items")
440
+ if not isinstance(items, list) or not items:
441
+ return 400, {"ok": False, "message": "`items` must be a non-empty list."}
442
+ normalized_items = [dict(item) for item in items if isinstance(item, dict)]
443
+ if not normalized_items:
444
+ return 400, {"ok": False, "message": "`items` must contain query objects."}
445
+ try:
446
+ return self.app.admin_service.chart_query(normalized_items)
447
+ except FileNotFoundError as exc:
448
+ return 404, {"ok": False, "message": str(exc)}
449
+
450
+ def admin_audit(self, path: str) -> dict:
451
+ query = self.parse_query(path)
452
+ limit_raw = ((query.get("limit") or ["200"])[0] or "200").strip()
453
+ try:
454
+ limit = max(1, min(int(limit_raw), 1000))
455
+ except ValueError:
456
+ limit = 200
457
+ return self.app.admin_service.audit(limit=limit)
458
+
459
+ def admin_stats_summary(self) -> dict:
460
+ return self.app.admin_service.stats_summary()
461
+
462
+ def admin_search(self, path: str) -> dict | tuple[int, dict]:
463
+ query = self.parse_query(path)
464
+ term = ((query.get("q") or [""])[0] or "").strip()
465
+ if not term:
466
+ return 400, {"ok": False, "message": "`q` is required."}
467
+ limit_raw = ((query.get("limit") or ["100"])[0] or "100").strip()
468
+ try:
469
+ limit = max(1, min(int(limit_raw), 500))
470
+ except ValueError:
471
+ limit = 100
472
+ return self.app.admin_service.search(term, limit=limit)
473
+
474
+ def admin_issue_draft(self, body: dict | None = None) -> dict:
475
+ payload = body if isinstance(body, dict) else {}
476
+ return self.app.admin_service.issue_draft(
477
+ summary=str(payload.get("summary") or "").strip() or None,
478
+ user_notes=str(payload.get("user_notes") or "").strip() or None,
479
+ include_doctor=payload.get("include_doctor") is not False,
480
+ include_logs=payload.get("include_logs") is not False,
481
+ include_system_settings=payload.get("include_system_settings") is not False,
482
+ include_system_quirks=payload.get("include_system_quirks") is True,
483
+ )
484
+
485
+ def admin_controllers(self) -> dict:
486
+ return self.app.admin_service.controllers()
487
+
488
+ def admin_controller_run(self, controller_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
489
+ _unused = body or {}
490
+ try:
491
+ result = self.app.admin_service.controller_run(controller_id)
492
+ except FileNotFoundError:
493
+ return 404, {"ok": False, "message": f"Unknown controller `{controller_id}`."}
494
+ self.app.admin_service.write_audit(
495
+ action="controller.run",
496
+ controller_id=controller_id,
497
+ result=result,
498
+ )
499
+ return {"ok": True, "controller_id": controller_id, "result": result}
500
+
501
+ def admin_controller_toggle(self, controller_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
502
+ payload = body if isinstance(body, dict) else {}
503
+ if "enabled" not in payload:
504
+ return 400, {"ok": False, "message": "`enabled` is required."}
505
+ try:
506
+ controller = self.app.admin_service.controller_toggle(controller_id, enabled=bool(payload.get("enabled")))
507
+ except StopIteration:
508
+ return 404, {"ok": False, "message": f"Unknown controller `{controller_id}`."}
509
+ self.app.admin_service.write_audit(
510
+ action="controller.toggle",
511
+ controller_id=controller_id,
512
+ enabled=bool(payload.get("enabled")),
513
+ )
514
+ return {"ok": True, "controller": controller}
515
+
516
+ def admin_repairs(self, path: str) -> dict:
517
+ query = self.parse_query(path)
518
+ limit_raw = ((query.get("limit") or ["50"])[0] or "50").strip()
519
+ try:
520
+ limit = max(1, min(int(limit_raw), 200))
521
+ except ValueError:
522
+ limit = 50
523
+ return {
524
+ "ok": True,
525
+ "items": self.app.admin_repair_service.list_repairs(limit=limit),
526
+ }
527
+
528
+ def admin_repair_create(self, body: dict | None = None) -> dict | tuple[int, dict]:
529
+ payload = body if isinstance(body, dict) else {}
530
+ request_text = str(payload.get("request_text") or payload.get("message") or "").strip()
531
+ if not request_text:
532
+ return 400, {"ok": False, "message": "`request_text` is required."}
533
+ try:
534
+ repair = self.app.admin_repair_service.create_repair(
535
+ request_text=request_text,
536
+ source_page=str(payload.get("source_page") or "").strip() or None,
537
+ scope=str(payload.get("scope") or "system").strip() or "system",
538
+ targets=dict(payload.get("targets") or {}) if isinstance(payload.get("targets"), dict) else None,
539
+ repair_policy=str(payload.get("repair_policy") or "diagnose_only").strip() or "diagnose_only",
540
+ selected_paths=[str(item) for item in payload.get("selected_paths") or []] if isinstance(payload.get("selected_paths"), list) else None,
541
+ )
542
+ except ValueError as exc:
543
+ return 400, {"ok": False, "message": str(exc)}
544
+ self.app.admin_service.write_audit(
545
+ action="repair.create",
546
+ repair_id=repair.get("repair_id"),
547
+ ops_quest_id=repair.get("ops_quest_id"),
548
+ scope=repair.get("scope"),
549
+ )
550
+ return {"ok": True, "repair": repair}
551
+
552
+ def admin_repair_detail(self, repair_id: str) -> dict | tuple[int, dict]:
553
+ try:
554
+ repair = self.app.admin_repair_service.get_repair(repair_id)
555
+ except FileNotFoundError:
556
+ return 404, {"ok": False, "message": f"Unknown repair `{repair_id}`."}
557
+ return {"ok": True, "repair": repair}
558
+
559
+ def admin_repair_close(self, repair_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
560
+ _unused = body or {}
561
+ try:
562
+ repair = self.app.admin_repair_service.close_repair(repair_id)
563
+ except FileNotFoundError:
564
+ return 404, {"ok": False, "message": f"Unknown repair `{repair_id}`."}
565
+ self.app.admin_service.write_audit(
566
+ action="repair.close",
567
+ repair_id=repair.get("repair_id"),
568
+ ops_quest_id=repair.get("ops_quest_id"),
569
+ )
570
+ return {"ok": True, "repair": repair}
571
+
572
+ def admin_tasks(self, path: str) -> dict:
573
+ query = self.parse_query(path)
574
+ kind = ((query.get("kind") or [""])[0] or "").strip() or None
575
+ limit_raw = ((query.get("limit") or ["50"])[0] or "50").strip()
576
+ try:
577
+ limit = max(1, min(int(limit_raw), 200))
578
+ except ValueError:
579
+ limit = 50
580
+ return {
581
+ "ok": True,
582
+ "items": self.app.admin_task_service.list_tasks(kind=kind, limit=limit),
583
+ }
584
+
585
+ def admin_task_doctor_start(self, body: dict | None = None) -> dict:
586
+ _unused = body or {}
587
+ task = self.app.admin_task_service.start_doctor_task()
588
+ return {"ok": True, "task": task}
589
+
590
+ def admin_task_system_update_check_start(self, body: dict | None = None) -> dict:
591
+ _unused = body or {}
592
+ task = self.app.admin_task_service.start_system_update_check_task()
593
+ return {"ok": True, "task": task}
594
+
595
+ def admin_task_system_update_action_start(self, body: dict | None = None) -> dict | tuple[int, dict]:
596
+ payload = body if isinstance(body, dict) else {}
597
+ action = str(payload.get("action") or "").strip().lower()
598
+ if not action:
599
+ return 400, {"ok": False, "message": "`action` is required."}
600
+ try:
601
+ task = self.app.admin_task_service.start_system_update_action_task(action=action)
602
+ except ValueError as exc:
603
+ return 400, {"ok": False, "message": str(exc)}
604
+ return {"ok": True, "task": task}
605
+
606
+ def admin_task_detail(self, task_id: str) -> dict | tuple[int, dict]:
607
+ try:
608
+ task = self.app.admin_task_service.get_task(task_id)
609
+ except FileNotFoundError:
610
+ return 404, {"ok": False, "message": f"Unknown admin task `{task_id}`."}
611
+ return {
612
+ "ok": True,
613
+ "task": task,
614
+ }
615
+
616
+ def system_shutdown(self, body: dict | None = None) -> dict:
617
+ return self.admin_shutdown(body if isinstance(body, dict) else {})
618
+
619
+ def system_doctor(self) -> dict:
620
+ return self.admin_doctor()
621
+
622
+ def system_overview(self) -> dict:
623
+ return self.admin_overview()
624
+
625
+ def system_quests(self, path: str) -> dict:
626
+ return self.admin_quests(path)
627
+
628
+ def system_quest_summary(self, quest_id: str) -> dict | tuple[int, dict]:
629
+ return self.admin_quest_summary(quest_id)
630
+
631
+ def system_runtime_sessions(self, path: str) -> dict:
632
+ return self.admin_runtime_sessions(path)
633
+
634
+ def system_log_sources(self) -> dict:
635
+ return self.admin_log_sources()
636
+
637
+ def system_log_tail(self, path: str) -> dict | tuple[int, dict]:
638
+ return self.admin_log_tail(path)
639
+
640
+ def system_failures(self, path: str) -> dict:
641
+ return self.admin_failures(path)
642
+
643
+ def system_errors(self, path: str) -> dict:
644
+ return self.admin_errors(path)
645
+
646
+ def system_runtime_tools(self) -> dict:
647
+ return self.admin_runtime_tools()
648
+
649
+ def system_hardware(self) -> dict:
650
+ return self.admin_system_hardware()
651
+
652
+ def system_hardware_update(self, body: dict | None = None) -> dict | tuple[int, dict]:
653
+ return self.admin_system_hardware_update(body)
654
+
655
+ def system_chart_catalog(self) -> dict:
656
+ return self.admin_chart_catalog()
657
+
658
+ def system_chart_query(self, body: dict | None = None) -> dict | tuple[int, dict]:
659
+ return self.admin_chart_query(body)
660
+
661
+ def system_audit(self, path: str) -> dict:
662
+ return self.admin_audit(path)
663
+
664
+ def system_stats_summary(self) -> dict:
665
+ return self.admin_stats_summary()
666
+
667
+ def system_search(self, path: str) -> dict | tuple[int, dict]:
668
+ return self.admin_search(path)
669
+
670
+ def system_issue_draft(self, body: dict | None = None) -> dict:
671
+ return self.admin_issue_draft(body)
672
+
673
+ def system_controllers(self) -> dict:
674
+ return self.admin_controllers()
675
+
676
+ def system_controller_run(self, controller_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
677
+ return self.admin_controller_run(controller_id, body)
678
+
679
+ def system_controller_toggle(self, controller_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
680
+ return self.admin_controller_toggle(controller_id, body)
681
+
682
+ def system_repairs(self, path: str) -> dict:
683
+ return self.admin_repairs(path)
684
+
685
+ def system_repair_create(self, body: dict | None = None) -> dict | tuple[int, dict]:
686
+ return self.admin_repair_create(body)
687
+
688
+ def system_repair_detail(self, repair_id: str) -> dict | tuple[int, dict]:
689
+ return self.admin_repair_detail(repair_id)
690
+
691
+ def system_repair_close(self, repair_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
692
+ return self.admin_repair_close(repair_id, body)
693
+
694
+ def system_tasks(self, path: str) -> dict:
695
+ return self.admin_tasks(path)
696
+
697
+ def system_task_doctor_start(self, body: dict | None = None) -> dict:
698
+ return self.admin_task_doctor_start(body)
699
+
700
+ def system_task_system_update_check_start(self, body: dict | None = None) -> dict:
701
+ return self.admin_task_system_update_check_start(body)
702
+
703
+ def system_task_system_update_action_start(self, body: dict | None = None) -> dict | tuple[int, dict]:
704
+ return self.admin_task_system_update_action_start(body)
705
+
706
+ def system_task_detail(self, task_id: str) -> dict | tuple[int, dict]:
707
+ return self.admin_task_detail(task_id)
708
+
286
709
  def acp_status(self) -> dict:
287
710
  return get_acp_bridge_status().as_dict()
288
711
 
@@ -317,6 +740,108 @@ npm --prefix src/ui run build</pre>
317
740
  except ValueError as exc:
318
741
  return 400, {"ok": False, "message": str(exc), "baseline_id": baseline_id}
319
742
 
743
+ def benchstore_entries(self, path: str = "") -> dict:
744
+ try:
745
+ hardware = self.app.admin_service.system_hardware(refresh=False)
746
+ except Exception:
747
+ hardware = {}
748
+ return self.app.benchstore_service.list_entries(hardware_payload=hardware, locale=self._locale_from_path(path))
749
+
750
+ def benchstore_entry(self, entry_id: str, path: str = "") -> dict | tuple[int, dict]:
751
+ try:
752
+ hardware = self.app.admin_service.system_hardware(refresh=False)
753
+ except Exception:
754
+ hardware = {}
755
+ try:
756
+ return self.app.benchstore_service.get_entry(entry_id, hardware_payload=hardware, locale=self._locale_from_path(path))
757
+ except FileNotFoundError as exc:
758
+ return 404, {"ok": False, "message": str(exc), "entry_id": entry_id}
759
+
760
+ def benchstore_entry_image(self, entry_id: str, path: str = "") -> tuple[int, dict, bytes]:
761
+ try:
762
+ path = self.app.benchstore_service.entry_image_asset_path(entry_id, locale=self._locale_from_path(path))
763
+ except FileNotFoundError as exc:
764
+ return 404, {"Content-Type": "text/plain; charset=utf-8"}, str(exc).encode("utf-8")
765
+ mime_type = self._guess_static_mime_type(path)
766
+ return 200, self._asset_headers(mime_type), path.read_bytes()
767
+
768
+ def benchstore_entry_install(self, entry_id: str, body: dict | None = None) -> dict | tuple[int, dict]:
769
+ _unused = body or {}
770
+ try:
771
+ task = self.app.start_benchstore_install(entry_id)
772
+ except FileNotFoundError as exc:
773
+ return 404, {"ok": False, "message": str(exc), "entry_id": entry_id}
774
+ except ValueError as exc:
775
+ return 400, {"ok": False, "message": str(exc), "entry_id": entry_id}
776
+ return {"ok": True, "entry_id": entry_id, "task": task}
777
+
778
+ def benchstore_entry_setup_packet(self, entry_id: str, path: str = "") -> dict | tuple[int, dict]:
779
+ try:
780
+ hardware = self.app.admin_service.system_hardware(refresh=False)
781
+ except Exception:
782
+ hardware = {}
783
+ try:
784
+ setup_packet = self.app.benchstore_service.build_setup_packet(
785
+ entry_id=entry_id,
786
+ hardware_payload=hardware,
787
+ locale=self._locale_from_path(path, default="zh"),
788
+ )
789
+ except FileNotFoundError as exc:
790
+ return 404, {"ok": False, "message": str(exc), "entry_id": entry_id}
791
+ except ValueError as exc:
792
+ return 409, {"ok": False, "message": str(exc), "entry_id": entry_id}
793
+ return {"ok": True, "entry_id": entry_id, "setup_packet": setup_packet}
794
+
795
+ def benchstore_entry_launch(self, entry_id: str, path: str = "", body: dict | None = None) -> dict | tuple[int, dict]:
796
+ _unused = body or {}
797
+ try:
798
+ hardware = self.app.admin_service.system_hardware(refresh=False)
799
+ except Exception:
800
+ hardware = {}
801
+ try:
802
+ setup_packet = self.app.benchstore_service.build_setup_packet(
803
+ entry_id=entry_id,
804
+ hardware_payload=hardware,
805
+ locale=self._locale_from_path(path, default="zh"),
806
+ )
807
+ except FileNotFoundError as exc:
808
+ return 404, {"ok": False, "message": str(exc), "entry_id": entry_id}
809
+ except ValueError as exc:
810
+ return 409, {"ok": False, "message": str(exc), "entry_id": entry_id}
811
+
812
+ launch_payload = setup_packet.get("launch_payload") if isinstance(setup_packet.get("launch_payload"), dict) else {}
813
+ goal = str(launch_payload.get("goal") or "").strip()
814
+ title = str(launch_payload.get("title") or "").strip() or None
815
+ initial_message = str(launch_payload.get("initial_message") or goal).strip() or goal
816
+ startup_contract = launch_payload.get("startup_contract") if isinstance(launch_payload.get("startup_contract"), dict) else None
817
+ if not goal:
818
+ return 400, {"ok": False, "message": "BenchStore launch payload is missing `goal`.", "entry_id": entry_id}
819
+
820
+ snapshot = self.app.create_quest(
821
+ goal=goal,
822
+ title=title,
823
+ quest_id=f"B-{self.app.quest_service.preview_next_numeric_quest_id()}",
824
+ source="benchstore",
825
+ startup_contract=startup_contract,
826
+ auto_bind_latest_connectors=False,
827
+ )
828
+ workspace_mode = str((startup_contract or {}).get("workspace_mode") or "").strip().lower()
829
+ if workspace_mode in {"copilot", "autonomous"}:
830
+ quest_root = self.app.quest_service._quest_root(snapshot["quest_id"])
831
+ self.app.quest_service.update_research_state(quest_root, workspace_mode=workspace_mode)
832
+ startup = self.app.submit_user_message(
833
+ snapshot["quest_id"],
834
+ text=initial_message,
835
+ source="benchstore",
836
+ )
837
+ return {
838
+ "ok": True,
839
+ "entry_id": entry_id,
840
+ "setup_packet": setup_packet,
841
+ "startup": startup,
842
+ "snapshot": self.app.quest_service.snapshot(snapshot["quest_id"]),
843
+ }
844
+
320
845
  def qq_bindings(self) -> list[dict]:
321
846
  return self.app.list_qq_bindings()
322
847
 
@@ -332,8 +857,13 @@ npm --prefix src/ui run build</pre>
332
857
  def connector_inbound(self, connector: str, body: dict) -> dict:
333
858
  return self.app.handle_connector_inbound(connector, body)
334
859
 
335
- def quests(self) -> list[dict]:
336
- return self.app.quest_service.list_quests()
860
+ def quests(self, path: str | None = None) -> list[dict]:
861
+ hidden_prefixes = ('b-', 's-')
862
+ return [
863
+ item
864
+ for item in self.app.quest_service.list_quests()
865
+ if not str(item.get('quest_id') or '').strip().lower().startswith(hidden_prefixes)
866
+ ]
337
867
 
338
868
  def quest_next_id(self) -> dict:
339
869
  return {
@@ -540,18 +1070,41 @@ npm --prefix src/ui run build</pre>
540
1070
  "active_anchor": body.get("active_anchor") if "active_anchor" in body else None,
541
1071
  "default_runner": body.get("default_runner") if "default_runner" in body else None,
542
1072
  "workspace_mode": body.get("workspace_mode") if "workspace_mode" in body else None,
1073
+ "decision_policy": body.get("decision_policy") if "decision_policy" in body else None,
543
1074
  }
544
1075
  if all(value is None for value in updates.values()):
545
1076
  return {
546
1077
  "ok": True,
547
1078
  "snapshot": self.app.quest_service.snapshot(quest_id),
548
1079
  }
1080
+ previous_snapshot = self.app.quest_service.snapshot(quest_id) if updates.get("workspace_mode") or updates.get("decision_policy") else None
549
1081
  try:
550
1082
  snapshot = self.app.quest_service.update_settings(quest_id, **updates)
551
1083
  except FileNotFoundError:
552
1084
  return 404, {"ok": False, "message": f"Unknown quest `{quest_id}`."}
553
1085
  except ValueError as exc:
554
1086
  return 400, {"ok": False, "message": str(exc)}
1087
+ # When switching from copilot to autonomous, continue safely without
1088
+ # replaying stale history-only user messages.
1089
+ if previous_snapshot is not None and (updates.get("workspace_mode") or updates.get("decision_policy")):
1090
+ prev_policy = str(previous_snapshot.get("continuation_policy") or "").strip().lower()
1091
+ new_policy = str(snapshot.get("continuation_policy") or "").strip().lower()
1092
+ prev_status = str(previous_snapshot.get("status") or previous_snapshot.get("runtime_status") or "").strip().lower()
1093
+ if (
1094
+ prev_policy == "wait_for_user_or_resume"
1095
+ and new_policy == "auto"
1096
+ and prev_status not in {"completed", "paused", "stopped", "error"}
1097
+ and not str(previous_snapshot.get("active_run_id") or "").strip()
1098
+ ):
1099
+ if int(snapshot.get("pending_user_message_count") or 0) > 0:
1100
+ self.app.schedule_turn(quest_id, reason="queued_user_messages")
1101
+ else:
1102
+ self.app.submit_user_message(
1103
+ quest_id,
1104
+ text="Continue",
1105
+ source="local",
1106
+ )
1107
+ snapshot = self.app.quest_service.snapshot(quest_id)
555
1108
  return {
556
1109
  "ok": True,
557
1110
  "snapshot": snapshot,
@@ -623,6 +1176,10 @@ npm --prefix src/ui run build</pre>
623
1176
  limit=limit,
624
1177
  tail=tail,
625
1178
  )
1179
+ payload["events"] = [
1180
+ self.app.quest_service.enrich_conversation_message_event(quest_id, event)
1181
+ for event in payload["events"]
1182
+ ]
626
1183
  if format_name in {"acp", "both"}:
627
1184
  payload["acp_updates"] = [
628
1185
  build_session_update(
@@ -892,6 +1449,26 @@ npm --prefix src/ui run build</pre>
892
1449
  return {"ok": False, "message": "Quest control action must be `pause`, `stop` or `resume`."}
893
1450
  return self.app.control_quest(quest_id, action=action, source=source)
894
1451
 
1452
+ def quest_message_read_now(self, quest_id: str, body: dict) -> dict:
1453
+ source = str(body.get("source") or "local-ui").strip() or "local-ui"
1454
+ message_id = str(body.get("message_id") or "").strip() or None
1455
+ client_message_id = str(body.get("client_message_id") or "").strip() or None
1456
+ return self.app.read_queued_user_messages_now(
1457
+ quest_id,
1458
+ message_id=message_id,
1459
+ client_message_id=client_message_id,
1460
+ source=source,
1461
+ )
1462
+
1463
+ def quest_message_withdraw(self, quest_id: str, body: dict) -> dict:
1464
+ source = str(body.get("source") or "local-ui").strip() or "local-ui"
1465
+ message_id = str(body.get("message_id") or "").strip() or None
1466
+ return self.app.withdraw_queued_user_message(
1467
+ quest_id,
1468
+ message_id=message_id or "",
1469
+ source=source,
1470
+ )
1471
+
895
1472
  def workflow(self, quest_id: str) -> dict:
896
1473
  payload = self.app.quest_service.workflow(quest_id)
897
1474
  projection_state = str(((payload or {}).get("projection_status") or {}).get("state") or "").strip().lower()
@@ -959,194 +1536,7 @@ npm --prefix src/ui run build</pre>
959
1536
 
960
1537
  def git_branches(self, quest_id: str) -> dict:
961
1538
  quest_root = self._fresh_quest_service()._quest_root(quest_id)
962
- payload = self.app.quest_service.git_branch_canvas(quest_id)
963
- research_state = self.app.quest_service.read_research_state(quest_root)
964
- active_workspace_branch = str(research_state.get("current_workspace_branch") or "").strip() or None
965
- research_head_branch = str(research_state.get("research_head_branch") or "").strip() or None
966
- payload["active_workspace_ref"] = active_workspace_branch
967
- payload["research_head_ref"] = research_head_branch
968
- payload["workspace_mode"] = str(research_state.get("workspace_mode") or "quest").strip() or "quest"
969
- projection_state = str(((payload or {}).get("projection_status") or {}).get("state") or "").strip().lower()
970
- if projection_state and projection_state != "ready" and not (payload.get("nodes") or []):
971
- return payload
972
- quest_data = self.app.quest_service.read_quest_yaml(quest_root)
973
- active_anchor = str(quest_data.get("active_anchor") or "").strip().lower()
974
- active_analysis_campaign_id = str(research_state.get("active_analysis_campaign_id") or "").strip() or None
975
- current_workspace_branch = str(research_state.get("current_workspace_branch") or "").strip() or None
976
- workspace_mode = str(research_state.get("workspace_mode") or "").strip().lower() or "quest"
977
- paper_parent_branch = str(research_state.get("paper_parent_branch") or "").strip() or None
978
- paper_parent_run_id = str(research_state.get("paper_parent_run_id") or "").strip() or None
979
- next_pending_slice_id = str(research_state.get("next_pending_slice_id") or "").strip() or None
980
- try:
981
- branch_summary = self.app.artifact_service.list_research_branches(quest_root)
982
- except Exception:
983
- branch_summary = {"branches": []}
984
- try:
985
- optimization_frontier = self.app.artifact_service.get_optimization_frontier(quest_root)
986
- except Exception:
987
- optimization_frontier = {"ok": False}
988
- branch_summary_by_name = {
989
- str(item.get("branch_name") or "").strip(): item
990
- for item in (branch_summary.get("branches") or [])
991
- if str(item.get("branch_name") or "").strip()
992
- }
993
- frontier_payload = (
994
- dict(optimization_frontier.get("optimization_frontier") or {})
995
- if isinstance(optimization_frontier, dict)
996
- and isinstance(optimization_frontier.get("optimization_frontier"), dict)
997
- else {}
998
- )
999
- best_branch_name = str(((frontier_payload.get("best_branch") or {}) if isinstance(frontier_payload.get("best_branch"), dict) else {}).get("branch_name") or "").strip() or None
1000
- stagnant_branch_names = {
1001
- str(item.get("branch_name") or "").strip()
1002
- for item in (frontier_payload.get("stagnant_branches") or [])
1003
- if isinstance(item, dict) and str(item.get("branch_name") or "").strip()
1004
- }
1005
- fusion_candidate_names = {
1006
- str(item.get("branch_name") or "").strip()
1007
- for item in (frontier_payload.get("fusion_candidates") or [])
1008
- if isinstance(item, dict) and str(item.get("branch_name") or "").strip()
1009
- }
1010
- candidate_count_by_branch: dict[str, int] = {}
1011
- for item in frontier_payload.get("implementation_candidates") or []:
1012
- if not isinstance(item, dict):
1013
- continue
1014
- branch_name = str(item.get("branch") or "").strip()
1015
- if not branch_name:
1016
- continue
1017
- candidate_count_by_branch[branch_name] = candidate_count_by_branch.get(branch_name, 0) + 1
1018
- active_campaign = {}
1019
- if active_analysis_campaign_id:
1020
- try:
1021
- active_campaign = self.app.artifact_service.get_analysis_campaign(
1022
- quest_root,
1023
- campaign_id=active_analysis_campaign_id,
1024
- )
1025
- except Exception:
1026
- active_campaign = {}
1027
- campaign_parent_branch = (
1028
- str(active_campaign.get("parent_branch") or "").strip() or None
1029
- if isinstance(active_campaign, dict)
1030
- else None
1031
- )
1032
- campaign_paper_line_branch = (
1033
- str(active_campaign.get("paper_line_branch") or "").strip() or None
1034
- if isinstance(active_campaign, dict)
1035
- else None
1036
- )
1037
- campaign_slices = [
1038
- dict(item)
1039
- for item in ((active_campaign or {}).get("slices") or [])
1040
- if isinstance(item, dict)
1041
- ]
1042
- campaign_total_slices = len(campaign_slices)
1043
- campaign_completed_slices = sum(
1044
- 1 for item in campaign_slices if str(item.get("status") or "").strip().lower() == "completed"
1045
- )
1046
- slice_by_branch = {
1047
- str(item.get("branch") or "").strip(): item
1048
- for item in campaign_slices
1049
- if str(item.get("branch") or "").strip()
1050
- }
1051
-
1052
- def resolve_workflow_state(ref: str, summary: dict[str, object] | None) -> dict[str, object]:
1053
- branch_kind = self.app.artifact_service._branch_kind_from_name(ref)
1054
- has_main_result = bool((summary or {}).get("has_main_result"))
1055
- workflow_state: dict[str, object] = {
1056
- "analysis_state": "none",
1057
- "writing_state": "not_ready",
1058
- "analysis_campaign_id": active_analysis_campaign_id,
1059
- "total_slices": campaign_total_slices or None,
1060
- "completed_slices": campaign_completed_slices or None,
1061
- "next_pending_slice_id": next_pending_slice_id,
1062
- "paper_parent_branch": paper_parent_branch,
1063
- "paper_parent_run_id": paper_parent_run_id,
1064
- "status_reason": None,
1065
- }
1066
- if branch_kind == "analysis":
1067
- slice_entry = slice_by_branch.get(ref)
1068
- slice_status = str((slice_entry or {}).get("status") or "pending").strip().lower() or "pending"
1069
- if slice_status == "completed":
1070
- workflow_state["analysis_state"] = "completed"
1071
- workflow_state["status_reason"] = "Analysis slice completed."
1072
- elif ref == current_workspace_branch or str((slice_entry or {}).get("slice_id") or "").strip() == next_pending_slice_id:
1073
- workflow_state["analysis_state"] = "active"
1074
- workflow_state["status_reason"] = (
1075
- f"Analysis {campaign_completed_slices}/{campaign_total_slices} done"
1076
- if campaign_total_slices
1077
- else "Analysis slice active."
1078
- )
1079
- else:
1080
- workflow_state["analysis_state"] = "pending"
1081
- workflow_state["status_reason"] = "Analysis slice pending."
1082
- return workflow_state
1083
- if branch_kind == "paper":
1084
- if campaign_paper_line_branch and ref == campaign_paper_line_branch and next_pending_slice_id is not None:
1085
- workflow_state["analysis_state"] = "active"
1086
- workflow_state["writing_state"] = "blocked_by_analysis"
1087
- workflow_state["status_reason"] = (
1088
- f"Analysis {campaign_completed_slices}/{campaign_total_slices} done"
1089
- + (f" · next: {next_pending_slice_id}" if next_pending_slice_id else "")
1090
- )
1091
- return workflow_state
1092
- if ref == current_workspace_branch and workspace_mode == "paper":
1093
- workflow_state["writing_state"] = "completed" if active_anchor == "finalize" else "active"
1094
- workflow_state["status_reason"] = (
1095
- "Writing finalized." if active_anchor == "finalize" else "Writing workspace active."
1096
- )
1097
- else:
1098
- workflow_state["writing_state"] = "ready"
1099
- workflow_state["status_reason"] = "Writing workspace prepared."
1100
- return workflow_state
1101
- if campaign_parent_branch and not campaign_paper_line_branch and ref == campaign_parent_branch:
1102
- workflow_state["analysis_state"] = "completed" if next_pending_slice_id is None else "active"
1103
- if has_main_result:
1104
- workflow_state["writing_state"] = "ready" if next_pending_slice_id is None else "blocked_by_analysis"
1105
- workflow_state["status_reason"] = (
1106
- "Analysis complete. Ready for writing."
1107
- if next_pending_slice_id is None
1108
- else (
1109
- f"Analysis {campaign_completed_slices}/{campaign_total_slices} done"
1110
- + (f" · next: {next_pending_slice_id}" if next_pending_slice_id else "")
1111
- )
1112
- )
1113
- return workflow_state
1114
- if has_main_result:
1115
- workflow_state["writing_state"] = "ready"
1116
- workflow_state["status_reason"] = "Main experiment recorded. Ready for writing."
1117
- return workflow_state
1118
- workflow_state["status_reason"] = "Awaiting main experiment result."
1119
- return workflow_state
1120
-
1121
- for node in payload.get("nodes", []):
1122
- ref = str(node.get("ref") or "").strip()
1123
- if not ref:
1124
- continue
1125
- summary = branch_summary_by_name.get(ref)
1126
- node["active_workspace"] = ref == active_workspace_branch
1127
- node["research_head"] = ref == research_head_branch
1128
- node["workflow_state"] = resolve_workflow_state(ref, summary if isinstance(summary, dict) else None)
1129
- if not isinstance(summary, dict):
1130
- continue
1131
- node["branch_no"] = summary.get("branch_no")
1132
- node["idea_title"] = summary.get("idea_title")
1133
- node["idea_problem"] = summary.get("idea_problem")
1134
- node["next_target"] = summary.get("next_target")
1135
- node["lineage_intent"] = summary.get("lineage_intent")
1136
- node["parent_branch"] = summary.get("parent_branch")
1137
- node["foundation_ref"] = summary.get("foundation_ref")
1138
- node["foundation_reason"] = summary.get("foundation_reason")
1139
- node["idea_md_path"] = summary.get("idea_md_path")
1140
- node["idea_draft_path"] = summary.get("idea_draft_path")
1141
- node["latest_main_experiment"] = summary.get("latest_main_experiment")
1142
- node["experiment_count"] = summary.get("experiment_count")
1143
- node["has_main_result"] = summary.get("has_main_result")
1144
- node["optimization_mode"] = frontier_payload.get("mode")
1145
- node["optimization_best"] = ref == best_branch_name
1146
- node["optimization_stagnant"] = ref in stagnant_branch_names
1147
- node["optimization_fusion_candidate"] = ref in fusion_candidate_names
1148
- node["optimization_candidate_count"] = candidate_count_by_branch.get(ref, 0)
1149
- return payload
1539
+ return self.app.artifact_service.get_research_canvas(quest_root)
1150
1540
 
1151
1541
  def git_canvas(self, quest_id: str) -> dict:
1152
1542
  quest_root = self._fresh_quest_service()._quest_root(quest_id)
@@ -1348,7 +1738,7 @@ npm --prefix src/ui run build</pre>
1348
1738
  if not path.exists() or not path.is_file():
1349
1739
  return 404, {"Content-Type": "text/plain; charset=utf-8"}, b"Not Found"
1350
1740
 
1351
- mime_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
1741
+ mime_type = self._guess_static_mime_type(path)
1352
1742
  return 200, {"Content-Type": mime_type}, path.read_bytes()
1353
1743
 
1354
1744
  def runs(self, quest_id: str) -> list[dict]:
@@ -1475,9 +1865,13 @@ npm --prefix src/ui run build</pre>
1475
1865
 
1476
1866
  def quest_memory(self, quest_id: str) -> list[dict]:
1477
1867
  quest_service = self._fresh_quest_service()
1478
- return self._fresh_memory_service().list_cards(
1479
- scope="quest",
1480
- quest_root=quest_service._quest_root(quest_id),
1868
+ quest_root = quest_service._require_initialized_quest_root(quest_id)
1869
+ memory_service = self._fresh_memory_service()
1870
+ return memory_service.list_visible_quest_cards(
1871
+ active_quest_root=quest_root,
1872
+ active_quest_id=quest_id,
1873
+ limit=30,
1874
+ include_shared=memory_service.shared_read_enabled(),
1481
1875
  )
1482
1876
 
1483
1877
  def documents(self, quest_id: str) -> list[dict]:
@@ -1605,13 +1999,13 @@ npm --prefix src/ui run build</pre>
1605
1999
  if not quest_service._git_revision_exists(quest_root, revision):
1606
2000
  return 404, {"Content-Type": "text/plain; charset=utf-8"}, b"Not Found"
1607
2001
  file_path = Path(relative)
1608
- mime_type = mimetypes.guess_type(file_path.name)[0] or "application/octet-stream"
2002
+ mime_type = self._guess_static_mime_type(file_path)
1609
2003
  content = quest_service._read_git_bytes(quest_root, revision, relative)
1610
2004
  return 200, self._asset_headers(mime_type), content
1611
2005
  path, _writable, _scope, _source_kind = quest_service.resolve_document(quest_id, document_id)
1612
2006
  if not path.exists() or not path.is_file():
1613
2007
  return 404, {"Content-Type": "text/plain; charset=utf-8"}, b"Not Found"
1614
- mime_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
2008
+ mime_type = self._guess_static_mime_type(path)
1615
2009
  return 200, self._asset_headers(mime_type), path.read_bytes()
1616
2010
 
1617
2011
  def document_open(self, quest_id: str, body: dict) -> dict:
@@ -1659,6 +2053,55 @@ npm --prefix src/ui run build</pre>
1659
2053
  except FileNotFoundError:
1660
2054
  return 404, {"ok": False, "message": f"Unknown quest `{quest_id}`."}
1661
2055
 
2056
+ def chat_upload_create(self, quest_id: str, body: dict) -> dict:
2057
+ file_name = str(body.get("file_name") or "").strip()
2058
+ mime_type = str(body.get("mime_type") or "").strip()
2059
+ content_base64 = str(body.get("content_base64") or "").strip()
2060
+ draft_id = str(body.get("draft_id") or "").strip() or None
2061
+ if not file_name:
2062
+ return {"ok": False, "message": "`file_name` is required."}
2063
+ if not content_base64:
2064
+ return {"ok": False, "message": "`content_base64` is required."}
2065
+ try:
2066
+ content = base64.b64decode(content_base64, validate=True)
2067
+ except (ValueError, TypeError):
2068
+ return {"ok": False, "message": "Invalid `content_base64` payload."}
2069
+ try:
2070
+ return self.app.quest_service.save_chat_attachment_draft(
2071
+ quest_id,
2072
+ file_name=file_name,
2073
+ mime_type=mime_type or None,
2074
+ content=content,
2075
+ draft_id=draft_id,
2076
+ )
2077
+ except FileNotFoundError:
2078
+ return 404, {"ok": False, "message": f"Unknown quest `{quest_id}`."}
2079
+
2080
+ def chat_upload_delete(self, quest_id: str, draft_id: str, body: dict | None = None) -> dict:
2081
+ try:
2082
+ return self.app.quest_service.delete_chat_attachment_draft(
2083
+ quest_id,
2084
+ draft_id=draft_id,
2085
+ )
2086
+ except FileNotFoundError:
2087
+ return 404, {"ok": False, "message": f"Unknown quest `{quest_id}`."}
2088
+
2089
+ def chat_upload_import(self, quest_id: str, body: dict) -> dict:
2090
+ source_quest_id = str(body.get("source_quest_id") or "").strip()
2091
+ attachments = [dict(item) for item in (body.get("attachments") or []) if isinstance(item, dict)]
2092
+ if not source_quest_id:
2093
+ return {"ok": False, "message": "`source_quest_id` is required."}
2094
+ if not attachments:
2095
+ return {"ok": False, "message": "`attachments` is required."}
2096
+ try:
2097
+ return self.app.quest_service.import_chat_attachment_drafts(
2098
+ quest_id,
2099
+ source_quest_id=source_quest_id,
2100
+ attachments=attachments,
2101
+ )
2102
+ except FileNotFoundError as exc:
2103
+ return 404, {"ok": False, "message": str(exc)}
2104
+
1662
2105
  def latex_init(self, project_id: str, body: dict) -> dict:
1663
2106
  return self.app.latex_service.init_project(
1664
2107
  project_id,
@@ -1712,17 +2155,35 @@ npm --prefix src/ui run build</pre>
1712
2155
 
1713
2156
  def chat(self, quest_id: str, body: dict) -> dict:
1714
2157
  text = body.get("text", "").strip()
1715
- if not text:
2158
+ attachment_draft_ids = [
2159
+ str(item or "").strip()
2160
+ for item in (body.get("attachment_draft_ids") or [])
2161
+ if str(item or "").strip()
2162
+ ]
2163
+ if not text and not attachment_draft_ids:
1716
2164
  return {"ok": False, "message": "Empty message."}
1717
2165
  source = body.get("source", "api")
1718
2166
  self.app.sessions.bind(quest_id, source)
1719
- payload = self.app.submit_user_message(
1720
- quest_id,
1721
- text=text,
1722
- source=source,
1723
- reply_to_interaction_id=body.get("reply_to_interaction_id"),
1724
- client_message_id=body.get("client_message_id"),
1725
- )
2167
+ try:
2168
+ if attachment_draft_ids:
2169
+ payload = self.app.submit_web_user_message(
2170
+ quest_id,
2171
+ text=text,
2172
+ source=source,
2173
+ attachment_draft_ids=attachment_draft_ids,
2174
+ reply_to_interaction_id=body.get("reply_to_interaction_id"),
2175
+ client_message_id=body.get("client_message_id"),
2176
+ )
2177
+ else:
2178
+ payload = self.app.submit_user_message(
2179
+ quest_id,
2180
+ text=text,
2181
+ source=source,
2182
+ reply_to_interaction_id=body.get("reply_to_interaction_id"),
2183
+ client_message_id=body.get("client_message_id"),
2184
+ )
2185
+ except FileNotFoundError as exc:
2186
+ return 404, {"ok": False, "message": str(exc)}
1726
2187
  return {
1727
2188
  "ok": True,
1728
2189
  "ack": f"Received for {quest_id}. Stored and queued for execution.",
@@ -1907,8 +2368,9 @@ npm --prefix src/ui run build</pre>
1907
2368
  config = self.app.config_manager.load_named("config")
1908
2369
  runners = self.app.config_manager.load_runners_config()
1909
2370
  snapshot = self.app.quest_service.snapshot(quest_id)
1910
- runner_name = str(body.get("runner") or snapshot.get("runner") or config.get("default_runner", "codex")).strip().lower()
1911
- runner_cfg = runners.get(runner_name, {})
2371
+ requested_runner = str(body.get("runner") or "").strip().lower()
2372
+ runner_name = self.app._resolve_enabled_runner_name(snapshot, requested_runner=requested_runner)
2373
+ runner_cfg = runners.get(runner_name, {}) if isinstance(runners.get(runner_name), dict) else {}
1912
2374
  if runner_cfg.get("enabled") is False:
1913
2375
  return {
1914
2376
  "ok": False,
@@ -2033,7 +2495,7 @@ npm --prefix src/ui run build</pre>
2033
2495
  path = resolve_within(docs_root, relative)
2034
2496
  if not path.exists() or not path.is_file():
2035
2497
  return 404, {"Content-Type": "text/plain; charset=utf-8"}, b"Not Found"
2036
- mime_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
2498
+ mime_type = self._guess_static_mime_type(path)
2037
2499
  return 200, self._asset_headers(mime_type), path.read_bytes()
2038
2500
 
2039
2501
  def config_files(self) -> list[dict]:
@@ -2074,6 +2536,17 @@ npm --prefix src/ui run build</pre>
2074
2536
  }
2075
2537
 
2076
2538
  def config_save(self, name: str, body: dict) -> dict:
2539
+ if name == "config" and isinstance(body.get("structured"), dict):
2540
+ default_runner = self.app.config_manager._normalize_runtime_runner_name(
2541
+ body["structured"].get("default_runner")
2542
+ )
2543
+ if default_runner in {"codex", "claude", "kimi", "opencode"}:
2544
+ os.environ["DEEPSCIENTIST_DEFAULT_RUNNER"] = default_runner
2545
+ os.environ["DEEPSCIENTIST_ENABLE_RUNNER"] = default_runner
2546
+ os.environ.pop("DS_DEFAULT_RUNNER", None)
2547
+ os.environ.pop("DS_ENABLE_RUNNER", None)
2548
+ os.environ.pop("DEEPSCIENTIST_ENABLE_RUNNERS", None)
2549
+ os.environ.pop("DS_ENABLE_RUNNERS", None)
2077
2550
  if isinstance(body.get("structured"), dict):
2078
2551
  result = self.app.config_manager.save_named_payload(name, body["structured"])
2079
2552
  else:
@@ -2107,21 +2580,29 @@ npm --prefix src/ui run build</pre>
2107
2580
  return {"ok": False, "summary": "Config test requires `name` and `content`."}
2108
2581
  return self.app.config_manager.test_named_text(body["name"], body["content"], live=bool(body.get("live", True)))
2109
2582
 
2583
+ def config_deepxiv_test(self, body: dict | None = None) -> dict:
2584
+ payload = body.get("structured") if isinstance((body or {}).get("structured"), dict) else None
2585
+ return self.app.config_manager.test_deepxiv_payload(payload)
2586
+
2110
2587
  def asset(self, asset_path: str) -> tuple[int, dict, bytes]:
2588
+ dist_root = self._ui_dist_root()
2111
2589
  candidate_roots = [
2590
+ dist_root / "assets" if dist_root is not None else None,
2112
2591
  self.app.repo_root / "src" / "ui" / "public" / "assets",
2113
2592
  self.app.repo_root / "assets",
2114
2593
  ]
2115
2594
  path = None
2116
2595
  for root in candidate_roots:
2596
+ if root is None:
2597
+ continue
2117
2598
  candidate = resolve_within(root, asset_path)
2118
2599
  if candidate.exists() and candidate.is_file():
2119
2600
  path = candidate
2120
2601
  break
2121
2602
  if path is None:
2122
2603
  return 404, {"Content-Type": "text/plain; charset=utf-8"}, b"Not Found"
2123
- mime_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
2124
- return 200, {"Content-Type": mime_type}, path.read_bytes()
2604
+ mime_type = self._guess_static_mime_type(path)
2605
+ return 200, self._asset_headers(mime_type), path.read_bytes()
2125
2606
 
2126
2607
  @staticmethod
2127
2608
  def parse_query(path: str) -> dict[str, list[str]]:
@@ -2130,6 +2611,12 @@ npm --prefix src/ui run build</pre>
2130
2611
  return parse_qs(path.split("?", 1)[1], keep_blank_values=True)
2131
2612
 
2132
2613
 
2614
+ @staticmethod
2615
+ def _locale_from_path(path: str, *, default: str = "en") -> str:
2616
+ query = ApiHandlers.parse_query(path)
2617
+ locale = ((query.get("locale") or [default])[0] or default).strip().lower()
2618
+ return "zh" if locale.startswith("zh") else "en"
2619
+
2133
2620
  @staticmethod
2134
2621
  def parse_body(raw: bytes) -> dict:
2135
2622
  if not raw: