specrails-desktop 2.30.2 → 2.31.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 (462) hide show
  1. package/README.md +28 -24
  2. package/client/dist/assets/{ActivityFeedPage-9DZOvIcY.js → ActivityFeedPage-CAhFRUO4.js} +1 -1
  3. package/client/dist/assets/{AgentBrowserCapture-DqyHbzk7.js → AgentBrowserCapture-Ct4G5lsE.js} +1 -1
  4. package/client/dist/assets/AgentModeCodePane-DQt9WIvu.js +2 -0
  5. package/client/dist/assets/{AgentModeJobsPane-CTIHMUKN.js → AgentModeJobsPane-podaJVl9.js} +1 -1
  6. package/client/dist/assets/AgentsPage-DTZdbW80.js +87 -0
  7. package/client/dist/assets/AnalyticsPage-BskgGPm0.js +1 -0
  8. package/client/dist/assets/CodePage-CvtYo1DU.js +2 -0
  9. package/client/dist/assets/{DesktopAnalyticsPage-CkXUFj3F.js → DesktopAnalyticsPage-Dnf99E8e.js} +1 -1
  10. package/client/dist/assets/{DocsDialog-PhdCJNVj.js → DocsDialog-DHi36rZ4.js} +1 -1
  11. package/client/dist/assets/{DocsPage-BY-wDthx.js → DocsPage-DIdVrQz1.js} +1 -1
  12. package/client/dist/assets/{InteractiveJobComposer-C9I0A4KR.js → InteractiveJobComposer-BHeB2inv.js} +1 -1
  13. package/client/dist/assets/{JobDetailModal-I_RoQJV4.js → JobDetailModal-CF1SKUHH.js} +1 -1
  14. package/client/dist/assets/JobDetailPage-De3rY18h.js +1 -0
  15. package/client/dist/assets/{JobsPage-DcllM4Ip.js → JobsPage-CfAqqJTx.js} +1 -1
  16. package/client/dist/assets/{LoopBuilderPage-DGm_iuff.js → LoopBuilderPage-DSBMuTb3.js} +2 -2
  17. package/client/dist/assets/{LoopPreviewModal-BC-TeFdD.js → LoopPreviewModal-B-c37kA0.js} +1 -1
  18. package/client/dist/assets/LoopsPage-DjnNXdmm.js +1 -0
  19. package/client/dist/assets/{MinimizedChatsContext-Cs34FPTz.js → MinimizedChatsContext-DIsnQMVz.js} +1 -1
  20. package/client/dist/assets/PluginsPage-DA5pQ_6u.js +2 -0
  21. package/client/dist/assets/{ProjectSettingsDialog-nEs-ENrE.js → ProjectSettingsDialog-DA23PSi6.js} +1 -1
  22. package/client/dist/assets/{TemplatePreviewModal-D4qW-J9B.js → TemplatePreviewModal-Cp7IQ-g2.js} +1 -1
  23. package/client/dist/assets/TicketDetailModal-BPD2i_0R.js +14 -0
  24. package/client/dist/assets/{Trans-CPISVji8.js → Trans-cWtExGkC.js} +1 -1
  25. package/client/dist/assets/addspec-4WmLJmBG.js +1 -0
  26. package/client/dist/assets/addspec-BRlk8jON.js +1 -0
  27. package/client/dist/assets/addspec-C7XRejU4.js +1 -0
  28. package/client/dist/assets/addspec-CHW9xf_X.js +1 -0
  29. package/client/dist/assets/addspec-DTmRrWrF.js +1 -0
  30. package/client/dist/assets/addspec-DhmnXER8.js +1 -0
  31. package/client/dist/assets/addspec-Di41DpYV.js +1 -0
  32. package/client/dist/assets/addspec-x3mizDxc.js +1 -0
  33. package/client/dist/assets/agent-BKsuIgIT.js +1 -0
  34. package/client/dist/assets/agent-Bs9NilfI.js +1 -0
  35. package/client/dist/assets/agent-C23h684q.js +1 -0
  36. package/client/dist/assets/agent-CqEjy3Z2.js +1 -0
  37. package/client/dist/assets/agent-D5DZTks1.js +1 -0
  38. package/client/dist/assets/agent-DE8hUYPl.js +1 -0
  39. package/client/dist/assets/agent-DsTuJGSc.js +1 -0
  40. package/client/dist/assets/agent-DwZM05-x.js +1 -0
  41. package/client/dist/assets/agents-45GbINfh.js +1 -0
  42. package/client/dist/assets/agents-BHp0_FQt.js +1 -0
  43. package/client/dist/assets/agents-Bvyi3y6R.js +1 -0
  44. package/client/dist/assets/agents-DMKFStHL.js +1 -0
  45. package/client/dist/assets/agents-DaYcxAr1.js +1 -0
  46. package/client/dist/assets/agents-IUOgqT5t.js +1 -0
  47. package/client/dist/assets/agents-ms7TwG16.js +1 -0
  48. package/client/dist/assets/agents-rzPnqoBR.js +1 -0
  49. package/client/dist/assets/agentstudio-8TQqBenW.js +1 -0
  50. package/client/dist/assets/agentstudio-B8Z_mmEX.js +1 -0
  51. package/client/dist/assets/agentstudio-BZR9YmLs.js +1 -0
  52. package/client/dist/assets/agentstudio-Bge9pAWb.js +1 -0
  53. package/client/dist/assets/agentstudio-Bz169Vzt.js +1 -0
  54. package/client/dist/assets/agentstudio-D6L2jpNi.js +1 -0
  55. package/client/dist/assets/agentstudio-K2-Z7CL0.js +1 -0
  56. package/client/dist/assets/agentstudio-Zmgzthv8.js +1 -0
  57. package/client/dist/assets/analytics-B8Qtptbl.js +1 -0
  58. package/client/dist/assets/analytics-BHqUazhP.js +1 -0
  59. package/client/dist/assets/analytics-BPptRY4f.js +1 -0
  60. package/client/dist/assets/analytics-BxDGOIwf.js +1 -0
  61. package/client/dist/assets/analytics-C9RaQcE3.js +1 -0
  62. package/client/dist/assets/analytics-CJIwqrEl.js +1 -0
  63. package/client/dist/assets/analytics-D_OZdQ9O.js +1 -0
  64. package/client/dist/assets/analytics-We6lUMI8.js +1 -0
  65. package/client/dist/assets/builder-3bygQtZi.js +1 -0
  66. package/client/dist/assets/builder-BiUG9Z5K.js +1 -0
  67. package/client/dist/assets/builder-CGRz_-zP.js +1 -0
  68. package/client/dist/assets/builder-CWYPw7Cw.js +1 -0
  69. package/client/dist/assets/builder-CX1437hF.js +1 -0
  70. package/client/dist/assets/{builder-CwA4T7gP.js → builder-Cowk9jtL.js} +1 -1
  71. package/client/dist/assets/builder-DwDexYRE.js +1 -0
  72. package/client/dist/assets/builder-skfnZ1uC.js +1 -0
  73. package/client/dist/assets/code-B0O8-p8k.js +1 -0
  74. package/client/dist/assets/code-B1VLZDhS.js +1 -0
  75. package/client/dist/assets/code-B86IMAfz.js +1 -0
  76. package/client/dist/assets/code-Bpj4Ddml.js +1 -0
  77. package/client/dist/assets/code-BykBZ5-e.js +1 -0
  78. package/client/dist/assets/code-CHPkOkDS.js +1 -0
  79. package/client/dist/assets/code-CkUuW4m9.js +1 -0
  80. package/client/dist/assets/code-cAqaqMTx.js +1 -0
  81. package/client/dist/assets/{dashboard-Dy2Um-US.js → dashboard-BVq6kRJe.js} +1 -1
  82. package/client/dist/assets/{dashboard-CHCEkds4.js → dashboard-BaKPPmLH.js} +1 -1
  83. package/client/dist/assets/{dashboard-CrlTV1ms.js → dashboard-Bm8e4zYG.js} +1 -1
  84. package/client/dist/assets/{dashboard-WhzOQw1S.js → dashboard-Bt6IesnM.js} +1 -1
  85. package/client/dist/assets/{dashboard-Cslu_GCH.js → dashboard-C_NQZle_.js} +1 -1
  86. package/client/dist/assets/{dashboard-DweT3Y4R.js → dashboard-CyZKoGoI.js} +1 -1
  87. package/client/dist/assets/{dashboard-DUU8-_Rg.js → dashboard-HIUdUBQ0.js} +1 -1
  88. package/client/dist/assets/{dashboard-Cqmmbh3l.js → dashboard-pm4Mr229.js} +1 -1
  89. package/client/dist/assets/{dist-js-jwoXo0YD.js → dist-js-BaP-xLOy.js} +1 -1
  90. package/client/dist/assets/{dist-js-Dj72W6qo.js → dist-js-CLlgOa5a.js} +1 -1
  91. package/client/dist/assets/format-command-C0D9IPmV.js +1 -0
  92. package/client/dist/assets/{formatDistanceToNow-ByKli7Q_.js → formatDistanceToNow-DUyzS4rr.js} +1 -1
  93. package/client/dist/assets/{getTimezoneOffsetInMilliseconds-qrcBaLW1.js → getTimezoneOffsetInMilliseconds-BCIwmmTj.js} +1 -1
  94. package/client/dist/assets/{i18n-Bf9Ckd10.js → i18n-D21Pr8Sj.js} +2 -2
  95. package/client/dist/assets/index-BdSDUFnA.css +2 -0
  96. package/client/dist/assets/index-Ci4-JKDr.js +77 -0
  97. package/client/dist/assets/{jobs-CVFD8rar.js → jobs-BAls3bWq.js} +1 -1
  98. package/client/dist/assets/{jobs-DoSaFzAa.js → jobs-B_TeSQxb.js} +1 -1
  99. package/client/dist/assets/jobs-Bgq-PZkC.js +1 -0
  100. package/client/dist/assets/jobs-Bpks6doU.js +1 -0
  101. package/client/dist/assets/jobs-CN_zv4Gr.js +1 -0
  102. package/client/dist/assets/jobs-DUlWSYq2.js +1 -0
  103. package/client/dist/assets/{jobs-B-sDHEay.js → jobs-DhxKgWFq.js} +1 -1
  104. package/client/dist/assets/{jobs-lk1_Dq1U.js → jobs-SwYS2M-B.js} +1 -1
  105. package/client/dist/assets/nav-BHDiSIVu.js +1 -0
  106. package/client/dist/assets/nav-CMiYAq4i.js +1 -0
  107. package/client/dist/assets/nav-CqS7NrDW.js +1 -0
  108. package/client/dist/assets/nav-D-0M7xfv.js +1 -0
  109. package/client/dist/assets/nav-D65O6u9I.js +1 -0
  110. package/client/dist/assets/nav-D_LKYvBr.js +1 -0
  111. package/client/dist/assets/nav-FDTJmU79.js +1 -0
  112. package/client/dist/assets/nav-VaB-C4k5.js +1 -0
  113. package/client/dist/assets/provider-capabilities-BvoExILy.js +1 -0
  114. package/client/dist/assets/settings-BveOJoaI.js +1 -0
  115. package/client/dist/assets/settings-Cj1C6F5k.js +1 -0
  116. package/client/dist/assets/settings-CuVwOpe0.js +1 -0
  117. package/client/dist/assets/settings-D5X4DfRc.js +1 -0
  118. package/client/dist/assets/settings-DXwxe-BW.js +1 -0
  119. package/client/dist/assets/settings-Di81Ba_V.js +1 -0
  120. package/client/dist/assets/settings-jbLjCYC_.js +1 -0
  121. package/client/dist/assets/settings-wIZNPFnn.js +1 -0
  122. package/client/dist/assets/setup-BBiHEO7h.js +1 -0
  123. package/client/dist/assets/setup-BlTWhNIQ.js +1 -0
  124. package/client/dist/assets/setup-Bp2L_oiP.js +1 -0
  125. package/client/dist/assets/setup-CInYXp1-.js +1 -0
  126. package/client/dist/assets/{setup-CITtPjed.js → setup-CYH3bP6K.js} +1 -1
  127. package/client/dist/assets/setup-DwcQ921P.js +1 -0
  128. package/client/dist/assets/setup-PBLjuDSs.js +1 -0
  129. package/client/dist/assets/setup-bx6FtoBp.js +1 -0
  130. package/client/dist/assets/{spending-DMnCXy84.js → spending-BCyUxoOI.js} +1 -1
  131. package/client/dist/assets/{tickets-B8BuAaj5.js → tickets-BL9r1G0e.js} +1 -1
  132. package/client/dist/assets/{tickets-DpmdE8tv.js → tickets-B_NyHJ8f.js} +1 -1
  133. package/client/dist/assets/{tickets-B_yh4qQk.js → tickets-BarF1wuG.js} +1 -1
  134. package/client/dist/assets/{tickets-pAUJkDTu.js → tickets-CclVhpQA.js} +1 -1
  135. package/client/dist/assets/{tickets-D_yDquEw.js → tickets-CqqOHbli.js} +1 -1
  136. package/client/dist/assets/{tickets-CFk2n2Or.js → tickets-DCkFSiqt.js} +1 -1
  137. package/client/dist/assets/{tickets-DQp7JS2R.js → tickets-Djn3ccfT.js} +1 -1
  138. package/client/dist/assets/{tickets-Bs37scwY.js → tickets-MiHBPsy_.js} +1 -1
  139. package/client/dist/assets/{useBrowserCaptureSession-CkBJShUw.js → useBrowserCaptureSession-CkVCDzer.js} +1 -1
  140. package/client/dist/assets/{useDesktop-B4pSBIDd.js → useDesktop-DCP_MHp9.js} +1 -1
  141. package/client/dist/index.html +25 -24
  142. package/docs/README.md +7 -3
  143. package/docs/cli.md +3 -3
  144. package/docs/codex.md +51 -64
  145. package/docs/creating-specs.md +36 -4
  146. package/docs/customizing.md +5 -5
  147. package/docs/gemini.md +35 -47
  148. package/docs/getting-started.md +15 -9
  149. package/docs/guide/de/agents/2-profiles-and-the-balanced-default.md +5 -1
  150. package/docs/guide/de/agents/4-custom-agents-catalog.md +7 -4
  151. package/docs/guide/de/getting-started/1-what-is-specrails.md +1 -0
  152. package/docs/guide/de/getting-started/2-installing-and-first-run.md +1 -0
  153. package/docs/guide/de/getting-started/4-the-dashboard-tour.md +4 -4
  154. package/docs/guide/de/integrations/1-ai-providers.md +29 -18
  155. package/docs/guide/de/integrations/2-plugins.md +3 -3
  156. package/docs/guide/de/integrations/6-agent-chat.md +8 -1
  157. package/docs/guide/de/pipeline/1-rails-and-jobs.md +9 -6
  158. package/docs/guide/de/pipeline/2-the-job-detail-view.md +3 -1
  159. package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  160. package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +13 -13
  161. package/docs/guide/de/pipeline/5-the-loop-builder.md +6 -2
  162. package/docs/guide/de/specs/2-add-spec-quick-mode.md +6 -1
  163. package/docs/guide/en/agents/2-profiles-and-the-balanced-default.md +7 -1
  164. package/docs/guide/en/agents/4-custom-agents-catalog.md +17 -4
  165. package/docs/guide/en/getting-started/1-what-is-specrails.md +2 -1
  166. package/docs/guide/en/getting-started/2-installing-and-first-run.md +2 -1
  167. package/docs/guide/en/getting-started/4-the-dashboard-tour.md +5 -5
  168. package/docs/guide/en/insights/3-code-explorer.md +5 -0
  169. package/docs/guide/en/integrations/1-ai-providers.md +63 -22
  170. package/docs/guide/en/integrations/2-plugins.md +3 -3
  171. package/docs/guide/en/integrations/6-agent-chat.md +14 -2
  172. package/docs/guide/en/pipeline/1-rails-and-jobs.md +19 -7
  173. package/docs/guide/en/pipeline/2-the-job-detail-view.md +3 -1
  174. package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  175. package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +25 -11
  176. package/docs/guide/en/pipeline/5-the-loop-builder.md +7 -2
  177. package/docs/guide/en/specs/2-add-spec-quick-mode.md +10 -1
  178. package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +5 -1
  179. package/docs/guide/es/agents/4-custom-agents-catalog.md +7 -4
  180. package/docs/guide/es/getting-started/1-what-is-specrails.md +1 -0
  181. package/docs/guide/es/getting-started/2-installing-and-first-run.md +1 -0
  182. package/docs/guide/es/getting-started/4-the-dashboard-tour.md +4 -4
  183. package/docs/guide/es/integrations/1-ai-providers.md +30 -18
  184. package/docs/guide/es/integrations/2-plugins.md +3 -3
  185. package/docs/guide/es/integrations/6-agent-chat.md +8 -1
  186. package/docs/guide/es/pipeline/1-rails-and-jobs.md +9 -6
  187. package/docs/guide/es/pipeline/2-the-job-detail-view.md +3 -1
  188. package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  189. package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +15 -13
  190. package/docs/guide/es/pipeline/5-the-loop-builder.md +6 -2
  191. package/docs/guide/es/specs/2-add-spec-quick-mode.md +6 -1
  192. package/docs/guide/fr/agents/2-profiles-and-the-balanced-default.md +5 -1
  193. package/docs/guide/fr/agents/4-custom-agents-catalog.md +7 -4
  194. package/docs/guide/fr/getting-started/1-what-is-specrails.md +1 -0
  195. package/docs/guide/fr/getting-started/2-installing-and-first-run.md +1 -0
  196. package/docs/guide/fr/getting-started/4-the-dashboard-tour.md +4 -4
  197. package/docs/guide/fr/integrations/1-ai-providers.md +29 -18
  198. package/docs/guide/fr/integrations/2-plugins.md +3 -3
  199. package/docs/guide/fr/integrations/6-agent-chat.md +8 -1
  200. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +9 -6
  201. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +3 -1
  202. package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  203. package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +15 -13
  204. package/docs/guide/fr/pipeline/5-the-loop-builder.md +6 -2
  205. package/docs/guide/fr/specs/2-add-spec-quick-mode.md +6 -1
  206. package/docs/guide/it/agents/2-profiles-and-the-balanced-default.md +5 -1
  207. package/docs/guide/it/agents/4-custom-agents-catalog.md +7 -4
  208. package/docs/guide/it/getting-started/1-what-is-specrails.md +1 -0
  209. package/docs/guide/it/getting-started/2-installing-and-first-run.md +1 -0
  210. package/docs/guide/it/getting-started/4-the-dashboard-tour.md +4 -4
  211. package/docs/guide/it/integrations/1-ai-providers.md +28 -18
  212. package/docs/guide/it/integrations/2-plugins.md +3 -3
  213. package/docs/guide/it/integrations/6-agent-chat.md +8 -1
  214. package/docs/guide/it/pipeline/1-rails-and-jobs.md +9 -6
  215. package/docs/guide/it/pipeline/2-the-job-detail-view.md +3 -1
  216. package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  217. package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +13 -13
  218. package/docs/guide/it/pipeline/5-the-loop-builder.md +6 -2
  219. package/docs/guide/it/specs/2-add-spec-quick-mode.md +6 -1
  220. package/docs/guide/ja/agents/2-profiles-and-the-balanced-default.md +6 -1
  221. package/docs/guide/ja/agents/4-custom-agents-catalog.md +7 -4
  222. package/docs/guide/ja/getting-started/1-what-is-specrails.md +1 -0
  223. package/docs/guide/ja/getting-started/2-installing-and-first-run.md +1 -0
  224. package/docs/guide/ja/getting-started/4-the-dashboard-tour.md +4 -4
  225. package/docs/guide/ja/integrations/1-ai-providers.md +28 -18
  226. package/docs/guide/ja/integrations/2-plugins.md +3 -3
  227. package/docs/guide/ja/integrations/6-agent-chat.md +7 -1
  228. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +9 -6
  229. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +3 -1
  230. package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  231. package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +14 -13
  232. package/docs/guide/ja/pipeline/5-the-loop-builder.md +6 -2
  233. package/docs/guide/ja/specs/2-add-spec-quick-mode.md +6 -1
  234. package/docs/guide/pt/agents/2-profiles-and-the-balanced-default.md +5 -1
  235. package/docs/guide/pt/agents/4-custom-agents-catalog.md +7 -4
  236. package/docs/guide/pt/getting-started/1-what-is-specrails.md +1 -0
  237. package/docs/guide/pt/getting-started/2-installing-and-first-run.md +1 -0
  238. package/docs/guide/pt/getting-started/4-the-dashboard-tour.md +4 -4
  239. package/docs/guide/pt/integrations/1-ai-providers.md +28 -18
  240. package/docs/guide/pt/integrations/2-plugins.md +3 -3
  241. package/docs/guide/pt/integrations/6-agent-chat.md +7 -1
  242. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +9 -6
  243. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +2 -1
  244. package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  245. package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +14 -13
  246. package/docs/guide/pt/pipeline/5-the-loop-builder.md +6 -2
  247. package/docs/guide/pt/specs/2-add-spec-quick-mode.md +6 -1
  248. package/docs/guide/zh/agents/2-profiles-and-the-balanced-default.md +4 -1
  249. package/docs/guide/zh/agents/4-custom-agents-catalog.md +7 -4
  250. package/docs/guide/zh/getting-started/1-what-is-specrails.md +1 -0
  251. package/docs/guide/zh/getting-started/2-installing-and-first-run.md +1 -0
  252. package/docs/guide/zh/getting-started/4-the-dashboard-tour.md +4 -4
  253. package/docs/guide/zh/integrations/1-ai-providers.md +26 -18
  254. package/docs/guide/zh/integrations/2-plugins.md +3 -3
  255. package/docs/guide/zh/integrations/6-agent-chat.md +6 -1
  256. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +9 -6
  257. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +2 -1
  258. package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +1 -1
  259. package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +12 -12
  260. package/docs/guide/zh/pipeline/5-the-loop-builder.md +6 -2
  261. package/docs/guide/zh/specs/2-add-spec-quick-mode.md +6 -1
  262. package/docs/internals/README.md +4 -1
  263. package/docs/internals/adding-a-provider.md +32 -28
  264. package/docs/internals/api-reference.md +37 -13
  265. package/docs/internals/architecture.md +5 -5
  266. package/docs/internals/bundled-framework-build-plan.md +3 -3
  267. package/docs/internals/code-explorer-story.md +4 -0
  268. package/docs/internals/configuration.md +17 -5
  269. package/docs/internals/global-artifacts-alignment-contract.md +1 -1
  270. package/docs/internals/operations-runbook.md +1 -1
  271. package/docs/internals/profiles.md +37 -45
  272. package/docs/internals/project-builder.md +16 -0
  273. package/docs/kimi.md +291 -0
  274. package/docs/mcp.md +9 -2
  275. package/docs/platforms/macos.md +17 -7
  276. package/docs/platforms/windows.md +9 -4
  277. package/docs/running-pipelines.md +46 -12
  278. package/docs/terminal.md +1 -1
  279. package/docs/tracking-cost.md +25 -6
  280. package/package.json +4 -2
  281. package/server/dist/agent-chat-manager.js +74 -32
  282. package/server/dist/agent-chat-router.js +40 -17
  283. package/server/dist/agent-cwd-manager.js +14 -7
  284. package/server/dist/agent-generator.js +69 -85
  285. package/server/dist/agent-mcp-config.js +17 -11
  286. package/server/dist/agent-operator-prompt.js +29 -20
  287. package/server/dist/agent-refine-manager.js +58 -38
  288. package/server/dist/ai-invocations.js +65 -20
  289. package/server/dist/attachment-manager.js +49 -15
  290. package/server/dist/blueprint-chat-manager.js +41 -16
  291. package/server/dist/blueprint-router.js +40 -6
  292. package/server/dist/chat-manager.js +165 -89
  293. package/server/dist/code-explorer-router.js +26 -7
  294. package/server/dist/contract-refine-runner.js +146 -113
  295. package/server/dist/core-compat.js +57 -2
  296. package/server/dist/core-package.js +3 -3
  297. package/server/dist/core-update-manager.js +17 -1
  298. package/server/dist/db.js +60 -5
  299. package/server/dist/desktop-analytics.js +44 -6
  300. package/server/dist/desktop-router.js +127 -11
  301. package/server/dist/explore-cwd-manager.js +19 -3
  302. package/server/dist/feature-flags.js +1 -1
  303. package/server/dist/file-story-manager.js +3 -3
  304. package/server/dist/file-summary-generator.js +21 -15
  305. package/server/dist/file-summary-manager.js +6 -6
  306. package/server/dist/framework-manager.js +19 -2
  307. package/server/dist/framework-migration.js +27 -12
  308. package/server/dist/install-config-path.js +1 -1
  309. package/server/dist/interactive-job-session.js +8 -6
  310. package/server/dist/loop-command-catalog.js +27 -10
  311. package/server/dist/loop-executors.js +59 -27
  312. package/server/dist/loop-factory.js +2 -2
  313. package/server/dist/loop-run-manager.js +100 -39
  314. package/server/dist/loops-router.js +1 -1
  315. package/server/dist/mcp/guide.js +23 -16
  316. package/server/dist/mcp/tools/agents.js +47 -41
  317. package/server/dist/mcp/tools/analytics.js +2 -2
  318. package/server/dist/mcp/tools/loops.js +2 -2
  319. package/server/dist/mcp/tools/plugins.js +14 -9
  320. package/server/dist/mcp/tools/rails.js +12 -13
  321. package/server/dist/mcp/tools/support.js +1 -1
  322. package/server/dist/mobile/mobile-router.js +5 -1
  323. package/server/dist/offline-assemble.js +13 -1
  324. package/server/dist/path-resolver.js +2 -2
  325. package/server/dist/plugin-manager.js +391 -106
  326. package/server/dist/plugins/claude-md-mutation.js +5 -4
  327. package/server/dist/plugins/drift.js +32 -29
  328. package/server/dist/plugins/rail-integration.js +13 -2
  329. package/server/dist/plugins/serena/install.js +25 -17
  330. package/server/dist/plugins/serena/manifest.js +22 -5
  331. package/server/dist/plugins/serena/verify.js +46 -16
  332. package/server/dist/plugins-router.js +59 -8
  333. package/server/dist/profile-manager.js +148 -36
  334. package/server/dist/profiles-router.js +311 -82
  335. package/server/dist/project-registry.js +2 -2
  336. package/server/dist/project-router-chat.js +17 -8
  337. package/server/dist/project-router-helpers.js +93 -5
  338. package/server/dist/project-router-jobs.js +76 -12
  339. package/server/dist/project-router-loop-runs.js +42 -14
  340. package/server/dist/project-router-settings.js +31 -10
  341. package/server/dist/project-router-setup.js +4 -5
  342. package/server/dist/project-router-spending.js +15 -3
  343. package/server/dist/project-router-tickets.js +187 -181
  344. package/server/dist/project-router.js +1 -0
  345. package/server/dist/proposal-manager.js +125 -85
  346. package/server/dist/providers/claude-adapter.js +14 -0
  347. package/server/dist/providers/codex-adapter.js +20 -0
  348. package/server/dist/providers/gemini-adapter.js +14 -0
  349. package/server/dist/providers/index.js +18 -1
  350. package/server/dist/providers/kimi-adapter.js +361 -0
  351. package/server/dist/providers/kimi-skill-prompt.js +332 -0
  352. package/server/dist/providers/runtime.js +137 -0
  353. package/server/dist/queue-manager.js +103 -78
  354. package/server/dist/rail-isolated-launch.js +1 -1
  355. package/server/dist/rails-router.js +51 -38
  356. package/server/dist/result-event.js +5 -0
  357. package/server/dist/schemas/profile.v1.json +3 -4
  358. package/server/dist/setup-manager.js +222 -101
  359. package/server/dist/setup-prerequisites.js +7 -1
  360. package/server/dist/smash-runner.js +104 -57
  361. package/server/dist/spawn-lifecycle.js +18 -14
  362. package/server/dist/spec-launcher-manager.js +66 -54
  363. package/server/dist/spec-models.js +15 -6
  364. package/server/dist/spending.js +110 -17
  365. package/server/dist/util/cli-prompt.js +142 -5
  366. package/server/dist/util/stream-display.js +46 -0
  367. package/server/dist/workspace-manager.js +100 -37
  368. package/server/dist/worktree-manager.js +4 -0
  369. package/server/dist/worktree-overlay.js +12 -3
  370. package/client/dist/assets/AgentModeCodePane-BAYyFRmY.js +0 -2
  371. package/client/dist/assets/AgentsPage-DuyJuaFs.js +0 -86
  372. package/client/dist/assets/AnalyticsPage-BY7gtCx6.js +0 -1
  373. package/client/dist/assets/CodePage-vyQr40Vl.js +0 -2
  374. package/client/dist/assets/JobDetailPage-CU4FEnUC.js +0 -1
  375. package/client/dist/assets/LoopsPage-SqglnXlp.js +0 -1
  376. package/client/dist/assets/PluginsPage-B89S8o1a.js +0 -2
  377. package/client/dist/assets/TicketDetailModal-CI47Dq9E.js +0 -14
  378. package/client/dist/assets/addspec-BXjvkh5q.js +0 -1
  379. package/client/dist/assets/addspec-C4bwrmpi.js +0 -1
  380. package/client/dist/assets/addspec-CArHXUDM.js +0 -1
  381. package/client/dist/assets/addspec-DTKJcXiR.js +0 -1
  382. package/client/dist/assets/addspec-DbNBbrha.js +0 -1
  383. package/client/dist/assets/addspec-Rw8uVBC1.js +0 -1
  384. package/client/dist/assets/addspec-htHGZHOe.js +0 -1
  385. package/client/dist/assets/addspec-lr_LP6jk.js +0 -1
  386. package/client/dist/assets/agent-BABjRt0P.js +0 -1
  387. package/client/dist/assets/agent-BuUpgqVx.js +0 -1
  388. package/client/dist/assets/agent-CCDZesgU.js +0 -1
  389. package/client/dist/assets/agent-CVn64zWH.js +0 -1
  390. package/client/dist/assets/agent-CWeOny0E.js +0 -1
  391. package/client/dist/assets/agent-DOysmad_.js +0 -1
  392. package/client/dist/assets/agent-DSsjTBhn.js +0 -1
  393. package/client/dist/assets/agent-DlZMxfM9.js +0 -1
  394. package/client/dist/assets/agents-6ZOJXWVk.js +0 -1
  395. package/client/dist/assets/agents-BZ0XQKjg.js +0 -1
  396. package/client/dist/assets/agents-BqWklnHR.js +0 -1
  397. package/client/dist/assets/agents-Bz-thHkB.js +0 -1
  398. package/client/dist/assets/agents-CJclElx6.js +0 -1
  399. package/client/dist/assets/agents-D_l9L0VA.js +0 -1
  400. package/client/dist/assets/agents-DhG7mg6-.js +0 -1
  401. package/client/dist/assets/agents-u_C0jPB5.js +0 -1
  402. package/client/dist/assets/agentstudio-BF19hbXj.js +0 -1
  403. package/client/dist/assets/agentstudio-BIUe1Im2.js +0 -1
  404. package/client/dist/assets/agentstudio-BLGvxWBx.js +0 -1
  405. package/client/dist/assets/agentstudio-D9UKiWTj.js +0 -1
  406. package/client/dist/assets/agentstudio-Drs37nIM.js +0 -1
  407. package/client/dist/assets/agentstudio-nEnKkcXM.js +0 -1
  408. package/client/dist/assets/agentstudio-pyFcSBKy.js +0 -1
  409. package/client/dist/assets/agentstudio-zfTzQh3U.js +0 -1
  410. package/client/dist/assets/analytics-BC7mwR4s.js +0 -1
  411. package/client/dist/assets/analytics-BiNg8edP.js +0 -1
  412. package/client/dist/assets/analytics-C0s_T2GN.js +0 -1
  413. package/client/dist/assets/analytics-CdsAPAwZ.js +0 -1
  414. package/client/dist/assets/analytics-Cr1_q-lC.js +0 -1
  415. package/client/dist/assets/analytics-DZ8Aoq3I.js +0 -1
  416. package/client/dist/assets/analytics-IEsKZvpW.js +0 -1
  417. package/client/dist/assets/analytics-SRPf84OT.js +0 -1
  418. package/client/dist/assets/builder-BH8Fua-g.js +0 -1
  419. package/client/dist/assets/builder-BoV7DgKd.js +0 -1
  420. package/client/dist/assets/builder-Cc_Lf79C.js +0 -1
  421. package/client/dist/assets/builder-CwZ7Bme2.js +0 -1
  422. package/client/dist/assets/builder-CxW-JFsR.js +0 -1
  423. package/client/dist/assets/builder-D94lrV7x.js +0 -1
  424. package/client/dist/assets/builder-cqHpCyGa.js +0 -1
  425. package/client/dist/assets/code-76gS0IdL.js +0 -1
  426. package/client/dist/assets/code-BDXEM4ml.js +0 -1
  427. package/client/dist/assets/code-C1VwxlML.js +0 -1
  428. package/client/dist/assets/code-CnMZyJpr.js +0 -1
  429. package/client/dist/assets/code-D20ef9Cf.js +0 -1
  430. package/client/dist/assets/code-DdOXaWRY.js +0 -1
  431. package/client/dist/assets/code-Duohuf9l.js +0 -1
  432. package/client/dist/assets/code-geHmknB9.js +0 -1
  433. package/client/dist/assets/format-command-Dfa1o2d-.js +0 -1
  434. package/client/dist/assets/index-Dh9i4CnN.css +0 -2
  435. package/client/dist/assets/index-F9r8mWP_.js +0 -76
  436. package/client/dist/assets/jobs-BCtGfgUA.js +0 -1
  437. package/client/dist/assets/jobs-BHR_EnDI.js +0 -1
  438. package/client/dist/assets/jobs-BMbZJjJJ.js +0 -1
  439. package/client/dist/assets/jobs-DzSIR8V6.js +0 -1
  440. package/client/dist/assets/nav-BRJBxaGt.js +0 -1
  441. package/client/dist/assets/nav-CAGKv3_F.js +0 -1
  442. package/client/dist/assets/nav-CNskRJKQ.js +0 -1
  443. package/client/dist/assets/nav-DY93irBL.js +0 -1
  444. package/client/dist/assets/nav-DhjvYgqt.js +0 -1
  445. package/client/dist/assets/nav-Gb-r4wop.js +0 -1
  446. package/client/dist/assets/nav-TvumAFD2.js +0 -1
  447. package/client/dist/assets/nav-myFaXRHD.js +0 -1
  448. package/client/dist/assets/settings-B0ypw9uw.js +0 -1
  449. package/client/dist/assets/settings-B9ilOSYO.js +0 -1
  450. package/client/dist/assets/settings-BqlWHRHA.js +0 -1
  451. package/client/dist/assets/settings-D8dlqt4d.js +0 -1
  452. package/client/dist/assets/settings-DAZqjX2a.js +0 -1
  453. package/client/dist/assets/settings-DRh39v1S.js +0 -1
  454. package/client/dist/assets/settings-Mj1OJbfd.js +0 -1
  455. package/client/dist/assets/settings-lRReaSYm.js +0 -1
  456. package/client/dist/assets/setup-3832BJCo.js +0 -1
  457. package/client/dist/assets/setup-B8J-gECe.js +0 -1
  458. package/client/dist/assets/setup-BCIOxVsc.js +0 -1
  459. package/client/dist/assets/setup-BciLj_tU.js +0 -1
  460. package/client/dist/assets/setup-CTkE3cfh.js +0 -1
  461. package/client/dist/assets/setup-ajB4rYm-.js +0 -1
  462. package/client/dist/assets/setup-xFO1wNl0.js +0 -1
@@ -10,9 +10,10 @@ const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const json_mutation_1 = require("./json-mutation");
12
12
  /**
13
- * Plugins contribute named sections to the project's top-level instructions
14
- * file (`CLAUDE.md` for claude projects, `AGENTS.md` for codex projects, and
15
- * the adapter-declared filename for future providers) so the agent's global
13
+ * Plugins contribute named sections to the project's provider-native
14
+ * instructions path (`CLAUDE.md` for Claude, `AGENTS.md` for Codex,
15
+ * `.kimi-code/AGENTS.md` for Kimi, and the adapter-declared path for future
16
+ * providers) so the agent's global
16
17
  * context includes per-plugin usage hints (e.g. "prefer Serena tools over
17
18
  * raw Read/Grep when locating symbols"). Each plugin owns one named block
18
19
  * delimited by HTML-comment markers; multiple plugins coexist without
@@ -88,7 +89,7 @@ function getBlockContent(projectPath, pluginName, filename = 'CLAUDE.md') {
88
89
  * file does not exist, it is created with just the block. If it exists
89
90
  * without our block, the block is appended at the end (separated by a blank
90
91
  * line). The filename defaults to `CLAUDE.md` for backwards compatibility;
91
- * codex projects pass `AGENTS.md`.
92
+ * other providers pass their adapter-declared relative path.
92
93
  */
93
94
  async function upsertBlock(projectPath, pluginName, content, filename = 'CLAUDE.md') {
94
95
  const file = instructionsMdPath(projectPath, filename);
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.detectMcpDrift = detectMcpDrift;
7
7
  const fs_1 = __importDefault(require("fs"));
8
- const paths_1 = require("./paths");
9
8
  const claude_md_mutation_1 = require("./claude-md-mutation");
9
+ const providers_1 = require("../providers");
10
10
  /**
11
11
  * Returns true when the project's `.mcp.json` entry for any of the plugin's
12
12
  * owned mcpServers no longer matches the bundled manifest. Used to surface
@@ -15,42 +15,45 @@ const claude_md_mutation_1 = require("./claude-md-mutation");
15
15
  *
16
16
  * Only inspects entries the plugin owns; user-authored entries are ignored.
17
17
  */
18
- function detectMcpDrift(projectPath, plugin) {
18
+ function detectMcpDrift(projectPath, plugin, providerId = 'claude') {
19
19
  const ownedKeys = plugin.manifest.owns.mcpServers ?? [];
20
- if (ownedKeys.length === 0)
21
- return false;
20
+ const adapter = (0, providers_1.hasAdapter)(providerId) ? (0, providers_1.getAdapter)(providerId) : (0, providers_1.getAdapter)('claude');
22
21
  // The plugin tells us what its current canonical entry should look like
23
22
  // via `previewInstall` is too heavy; we instead introspect via a marker:
24
23
  // plugins that ship their canonical entry expose it via `expectedMcpEntry`.
25
24
  // We accept Plugins without it (drift detection silently disabled).
26
- const expected = plugin
27
- .expectedMcpEntry?.();
28
- if (!expected)
29
- return false;
30
- const file = (0, paths_1.mcpJsonPath)(projectPath);
31
- if (!fs_1.default.existsSync(file))
32
- return false;
33
- let parsed;
34
- try {
35
- parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
25
+ const expected = plugin.expectedMcpEntry?.();
26
+ // CLI-managed registries (Codex) have no project JSON to compare. Their
27
+ // registration is checked by the plugin's verify hook instead.
28
+ if (expected &&
29
+ ownedKeys.length > 0 &&
30
+ adapter.mcpRegistration === 'project-json' &&
31
+ adapter.projectMcpPath) {
32
+ const file = adapter.projectMcpPath(projectPath);
33
+ if (fs_1.default.existsSync(file)) {
34
+ let parsed;
35
+ try {
36
+ parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ const servers = parsed.mcpServers ?? {};
42
+ for (const key of ownedKeys) {
43
+ const current = servers[key];
44
+ if (current === undefined)
45
+ continue;
46
+ if (JSON.stringify(current) !== JSON.stringify(expected))
47
+ return true;
48
+ }
49
+ }
36
50
  }
37
- catch {
38
- return false;
39
- }
40
- const servers = parsed.mcpServers ?? {};
41
- for (const key of ownedKeys) {
42
- const current = servers[key];
43
- if (current === undefined)
44
- continue;
45
- if (JSON.stringify(current) !== JSON.stringify(expected))
46
- return true;
47
- }
48
- // Shared-file contributor drift. Today only CLAUDE.md is contributed to;
49
- // we hardcode the comparison here. If/when more shared-file contributors
50
- // land we move this to a `compareDrift` hook on the contributor type.
51
+ // Provider-instructions contributor drift. The adapter path may be nested
52
+ // (for example Kimi's `.kimi-code/AGENTS.md`). If/when more shared-file
53
+ // contributors land we move this to a `compareDrift` hook.
51
54
  if (plugin.manifest.claudeMdInstructions) {
52
55
  const expectedMd = plugin.manifest.claudeMdInstructions.trim();
53
- const actualMd = ((0, claude_md_mutation_1.getBlockContent)(projectPath, plugin.manifest.name) ?? '').trim();
56
+ const actualMd = ((0, claude_md_mutation_1.getBlockContent)(projectPath, plugin.manifest.name, adapter.instructionsFilename) ?? '').trim();
54
57
  if (actualMd !== expectedMd)
55
58
  return true;
56
59
  }
@@ -20,7 +20,7 @@ const json_mutation_1 = require("./json-mutation");
20
20
  * actually changed since the last check (no churn on the steady-state path).
21
21
  * Otherwise this performs no project-file mutation.
22
22
  */
23
- async function resolvePluginsForSpawn(projectPath, projectId, _jobId) {
23
+ async function resolvePluginsForSpawn(projectPath, projectId, _jobId, providerId = 'claude', legacyProviderId = providerId, slug) {
24
24
  const mgr = (0, manager_1.getPluginManager)();
25
25
  const state = mgr.getProjectState(projectPath);
26
26
  const active = [];
@@ -28,13 +28,24 @@ async function resolvePluginsForSpawn(projectPath, projectId, _jobId) {
28
28
  // Run verify in parallel for all installed plugins. Each verify is
29
29
  // already timeout-wrapped inside PluginManager.
30
30
  const checks = await Promise.all(Object.entries(state.plugins).map(async ([name, entry]) => {
31
+ const scopedProviderState = entry.providers?.[providerId];
32
+ const providerInstalled = entry.providers
33
+ ? scopedProviderState !== undefined
34
+ : providerId === legacyProviderId;
35
+ // A plugin installed only for another provider must not appear in this
36
+ // rail's snapshot. Explicitly deactivated installs are intentionally
37
+ // absent rather than misreported as degraded.
38
+ if (!providerInstalled || scopedProviderState?.active === false)
39
+ return null;
31
40
  // Skip orphans — they are not in the registry, so verify cannot run.
32
41
  if (!mgr.registry.byName.has(name))
33
42
  return { name, version: entry.version, result: { ok: false, reason: 'orphan', checkedAt: new Date().toISOString() } };
34
- const result = await mgr.verify(projectPath, projectId, name);
43
+ const result = await mgr.verify(projectPath, projectId, name, undefined, providerId, legacyProviderId, slug);
35
44
  return { name, version: entry.version, result };
36
45
  }));
37
46
  for (const c of checks) {
47
+ if (!c)
48
+ continue;
38
49
  if (c.result.ok)
39
50
  active.push({ name: c.name, version: c.version });
40
51
  else
@@ -50,15 +50,20 @@ async function installSerena(ctx) {
50
50
  }
51
51
  return;
52
52
  }
53
- // Claude path: surgical merge of project's `.mcp.json` + custom agent
54
- // fragment. Unchanged from the pre-§14 behaviour.
55
- ctx.log('Adding mcpServers.serena to .mcp.json');
56
- await plugin_manager_1.PluginManager.mergeMcpServers(ctx.projectPath, { serena: manifest_1.SERENA_MCP_ENTRY });
57
- ctx.log(`Writing ${CLAUDE_FRAGMENT_REL}`);
58
- const fragmentDest = path_1.default.join(ctx.projectPath, CLAUDE_FRAGMENT_REL);
59
- fs_1.default.mkdirSync(path_1.default.dirname(fragmentDest), { recursive: true });
60
- fs_1.default.writeFileSync(fragmentDest, instructions_content_1.SERENA_INSTRUCTIONS_MD, 'utf8');
61
- ctx.recordInstalledFile(CLAUDE_FRAGMENT_REL);
53
+ const adapter = (0, providers_1.getAdapter)(ctx.providerId ?? 'claude');
54
+ const mcpFile = adapter.projectMcpPath?.(ctx.projectPath);
55
+ ctx.log(`Adding mcpServers.serena to ${mcpFile ?? '.mcp.json'}`);
56
+ await plugin_manager_1.PluginManager.mergeMcpServers(ctx.projectPath, { serena: manifest_1.SERENA_MCP_ENTRY }, adapter.id);
57
+ // Claude additionally receives its historical custom-agent fragment. Kimi
58
+ // consumes the provider-aware AGENTS.md contributor and native MCP config;
59
+ // its built-in subagents are not modelled as SpecRails roles.
60
+ if (adapter.id === 'claude') {
61
+ ctx.log(`Writing ${CLAUDE_FRAGMENT_REL}`);
62
+ const fragmentDest = path_1.default.join(ctx.projectPath, CLAUDE_FRAGMENT_REL);
63
+ fs_1.default.mkdirSync(path_1.default.dirname(fragmentDest), { recursive: true });
64
+ fs_1.default.writeFileSync(fragmentDest, instructions_content_1.SERENA_INSTRUCTIONS_MD, 'utf8');
65
+ ctx.recordInstalledFile(CLAUDE_FRAGMENT_REL);
66
+ }
62
67
  }
63
68
  async function uninstallSerena(ctx) {
64
69
  if (isCodex(ctx)) {
@@ -79,14 +84,17 @@ async function uninstallSerena(ctx) {
79
84
  }
80
85
  return;
81
86
  }
82
- ctx.log('Removing mcpServers.serena from .mcp.json');
83
- await plugin_manager_1.PluginManager.removeMcpServers(ctx.projectPath, ['serena']);
84
- const fragmentDest = path_1.default.join(ctx.projectPath, CLAUDE_FRAGMENT_REL);
85
- if (fs_1.default.existsSync(fragmentDest)) {
86
- ctx.log(`Removing ${CLAUDE_FRAGMENT_REL}`);
87
- try {
88
- fs_1.default.unlinkSync(fragmentDest);
87
+ const adapter = (0, providers_1.getAdapter)(ctx.providerId ?? 'claude');
88
+ ctx.log(`Removing mcpServers.serena from ${adapter.projectMcpPath?.(ctx.projectPath) ?? '.mcp.json'}`);
89
+ await plugin_manager_1.PluginManager.removeMcpServers(ctx.projectPath, ['serena'], adapter.id);
90
+ if (adapter.id === 'claude') {
91
+ const fragmentDest = path_1.default.join(ctx.projectPath, CLAUDE_FRAGMENT_REL);
92
+ if (fs_1.default.existsSync(fragmentDest)) {
93
+ ctx.log(`Removing ${CLAUDE_FRAGMENT_REL}`);
94
+ try {
95
+ fs_1.default.unlinkSync(fragmentDest);
96
+ }
97
+ catch { /* best-effort */ }
89
98
  }
90
- catch { /* best-effort */ }
91
99
  }
92
100
  }
@@ -60,13 +60,30 @@ exports.serenaManifest = {
60
60
  ],
61
61
  },
62
62
  },
63
+ kimi: {
64
+ mcpEntry: {
65
+ command: 'uvx',
66
+ args: [
67
+ '--from',
68
+ 'git+https://github.com/oraios/serena',
69
+ 'serena',
70
+ 'start-mcp-server',
71
+ '--context',
72
+ 'ide-assistant',
73
+ '--project',
74
+ '.',
75
+ '--enable-web-dashboard',
76
+ 'false',
77
+ ],
78
+ },
79
+ },
63
80
  },
64
81
  // Format: structured "when / tools / why / fallback" block. Lets generic
65
82
  // agent prompts (specrails-core sr-* "Tool Selection — Honor Project-
66
83
  // Documented MCP Tools" section) match the right entry to the task.
67
84
  //
68
- // Tool names below are verified against Serena's actual exposed tools
69
- // (visible in Claude session init's tools list). Keep this list aligned
85
+ // Tool names below are verified against Serena's actual exposed MCP tools.
86
+ // Keep this list aligned
70
87
  // with upstream — wrong names cause agents to mistrust the whole block.
71
88
  claudeMdInstructions: `## Plugin: serena (semantic code navigation)
72
89
 
@@ -85,11 +102,11 @@ exports.serenaManifest = {
85
102
  - \`replace_content\` — surgical text replace inside a single file when symbol-aware tools don't fit.
86
103
  - \`get_diagnostics_for_file\` — language-server diagnostics for a file.
87
104
 
88
- **Why prefer over built-ins**: Serena returns only the relevant symbol body, not whole files. Empirically cuts input tokens 40–60% on real workloads compared to \`Read\` / \`Grep\`.
105
+ **Why prefer over built-ins**: Serena returns only the relevant symbol body, not whole files. Empirically cuts input tokens 40–60% on real workloads compared with whole-file reads or broad text search.
89
106
 
90
- **Fallback to \`Read\` / \`Grep\` for**: binary files, free-form prose, structured data without symbols (logs, JSON without schema, plain Markdown).
107
+ **Fallback to the provider's built-in file/search tools for**: binary files, free-form prose, structured data without symbols (logs, JSON without schema, plain Markdown).
91
108
 
92
- **Subagents**: MCP access is inherited from the parent Claude session; pass these tool names through when delegating via the \`Task\` tool.`,
109
+ **Delegated agents**: when the active provider supports delegation, tell the delegated role to use these Serena tools. MCP inheritance is provider-owned, so verify availability in the delegated context and fall back to built-in file/search tools when needed.`,
93
110
  };
94
111
  exports.SERENA_MCP_ENTRY = {
95
112
  command: 'uvx',
@@ -1,24 +1,51 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.verifySerena = verifySerena;
4
7
  const child_process_1 = require("child_process");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
5
10
  const win_spawn_1 = require("../../util/win-spawn");
11
+ const providers_1 = require("../../providers");
12
+ const codex_mcp_1 = require("../codex-mcp");
6
13
  const TIMEOUT_MS = 1800;
7
- /**
8
- * Verify Serena availability. We only probe `uv --version` here — proxy for
9
- * "uvx will be able to launch serena-mcp-server when claude actually calls it".
10
- *
11
- * We intentionally do NOT shell out to `uvx --from git+... serena-mcp-server`:
12
- * that would download the git repo + dependencies on every verify, which is
13
- * slow (multi-second) and would fail offline. The Claude CLI itself triggers
14
- * the lazy install through uvx's own cache, so as long as `uv` is on PATH and
15
- * executable, install + spawn-time verify can both pass quickly.
16
- *
17
- * Cross-platform spawn: on Windows we set `shell: true` so PATH resolution
18
- * picks up `uv.exe` (or, if astral installed via winget, the .cmd shim) the
19
- * same way it does in `setup-prerequisites.ts`.
20
- */
21
- async function verifySerena() {
14
+ function registrationProblem(ctx) {
15
+ // Direct callers from the pre-provider API used verifySerena() as a cheap uv
16
+ // probe. Keep that contract; PluginManager always supplies provider context
17
+ // and therefore receives the stronger registration check below.
18
+ if (!ctx?.providerId)
19
+ return null;
20
+ if (!(0, providers_1.hasAdapter)(ctx.providerId))
21
+ return `unknown-provider:${ctx.providerId}`;
22
+ const adapter = (0, providers_1.getAdapter)(ctx.providerId);
23
+ if (adapter.mcpRegistration === 'cli-add') {
24
+ const slug = ctx.slug?.trim() || path_1.default.basename(ctx.projectPath);
25
+ const listing = (0, codex_mcp_1.codexMcpList)(slug);
26
+ if (!listing.ok)
27
+ return 'mcp-registry-unavailable';
28
+ return listing.servers.includes('serena') ? null : 'mcp-registration-missing';
29
+ }
30
+ const file = adapter.projectMcpPath?.(ctx.projectPath);
31
+ if (!file || !fs_1.default.existsSync(file))
32
+ return 'mcp-registration-missing';
33
+ try {
34
+ const parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
35
+ if (!parsed.mcpServers ||
36
+ typeof parsed.mcpServers !== 'object' ||
37
+ Array.isArray(parsed.mcpServers)) {
38
+ return 'mcp-registration-invalid';
39
+ }
40
+ return Object.prototype.hasOwnProperty.call(parsed.mcpServers, 'serena')
41
+ ? null
42
+ : 'mcp-registration-missing';
43
+ }
44
+ catch {
45
+ return 'mcp-registration-invalid';
46
+ }
47
+ }
48
+ async function verifySerena(ctx) {
22
49
  const checkedAt = new Date().toISOString();
23
50
  const isWin = process.platform === 'win32';
24
51
  return new Promise((resolve) => {
@@ -68,7 +95,10 @@ async function verifySerena() {
68
95
  settled = true;
69
96
  clearTimeout(timer);
70
97
  if (code === 0) {
71
- resolve({ ok: true, reason: undefined, checkedAt });
98
+ const reason = registrationProblem(ctx);
99
+ resolve(reason
100
+ ? { ok: false, reason, checkedAt }
101
+ : { ok: true, reason: undefined, checkedAt });
72
102
  }
73
103
  else {
74
104
  resolve({
@@ -8,6 +8,7 @@ const prereq_installer_1 = require("./plugins/prereq-installer");
8
8
  const path_resolver_1 = require("./path-resolver");
9
9
  const claude_approval_1 = require("./plugins/claude-approval");
10
10
  const workspace_resolution_1 = require("./workspace-resolution");
11
+ const providers_1 = require("./providers");
11
12
  /**
12
13
  * Relocate-artifacts gate: the dir the PluginManager mutates (`.mcp.json` +
13
14
  * `.specrails/plugins/` state + `.claude/agents/custom-*.md`). Relocated ⇒ the
@@ -41,6 +42,32 @@ function handleError(res, err) {
41
42
  const message = err instanceof Error ? err.message : 'unknown error';
42
43
  res.status(500).json({ error: message });
43
44
  }
45
+ /** Resolve the explicit provider projection for one plugin operation. Legacy
46
+ * clients that omit it keep targeting the project's primary provider. */
47
+ function requestedProvider(req, res, project) {
48
+ const bodyProvider = req.body?.provider;
49
+ const queryProvider = req.query.provider;
50
+ const raw = bodyProvider ?? queryProvider;
51
+ if (raw !== undefined &&
52
+ (typeof raw !== 'string' || raw.trim().length === 0)) {
53
+ res.status(400).json({ error: 'provider must be a non-empty string' });
54
+ return null;
55
+ }
56
+ const provider = typeof raw === 'string' ? raw.trim() : project.provider;
57
+ const configured = project.providers?.length > 0 ? project.providers : [project.provider];
58
+ if (!configured.includes(provider)) {
59
+ res.status(400).json({
60
+ error: `provider '${provider}' is not configured for this project`,
61
+ providers: configured,
62
+ });
63
+ return null;
64
+ }
65
+ if (!(0, providers_1.hasAdapter)(provider)) {
66
+ res.status(400).json({ error: `unknown provider '${provider}'` });
67
+ return null;
68
+ }
69
+ return provider;
70
+ }
44
71
  function createPluginsRouter() {
45
72
  const router = (0, express_1.Router)({ mergeParams: true });
46
73
  function ctx(req) {
@@ -57,7 +84,10 @@ function createPluginsRouter() {
57
84
  router.get('/', async (req, res) => {
58
85
  try {
59
86
  const { project } = ctx(req);
60
- const list = await (0, manager_1.getPluginManager)().listAvailable(pluginRoot(project), project.provider);
87
+ const provider = requestedProvider(req, res, project);
88
+ if (!provider)
89
+ return;
90
+ const list = await (0, manager_1.getPluginManager)().listAvailable(pluginRoot(project), provider, project.provider);
61
91
  res.json({ plugins: list });
62
92
  }
63
93
  catch (err) {
@@ -68,7 +98,10 @@ function createPluginsRouter() {
68
98
  router.get('/:name/preview-install', async (req, res) => {
69
99
  try {
70
100
  const { project } = ctx(req);
71
- const result = await (0, manager_1.getPluginManager)().previewInstall(pluginRoot(project), project.id, req.params.name);
101
+ const provider = requestedProvider(req, res, project);
102
+ if (!provider)
103
+ return;
104
+ const result = await (0, manager_1.getPluginManager)().previewInstall(pluginRoot(project), project.id, req.params.name, provider, project.slug);
72
105
  res.json(result);
73
106
  }
74
107
  catch (err) {
@@ -79,7 +112,10 @@ function createPluginsRouter() {
79
112
  router.post('/:name/install', async (req, res) => {
80
113
  try {
81
114
  const { project, broadcast } = ctx(req);
82
- await (0, manager_1.getPluginManager)().install(pluginRoot(project), project.id, req.params.name, broadcast, project.provider, project.slug);
115
+ const provider = requestedProvider(req, res, project);
116
+ if (!provider)
117
+ return;
118
+ await (0, manager_1.getPluginManager)().install(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.slug, project.provider);
83
119
  res.status(200).json({ ok: true });
84
120
  }
85
121
  catch (err) {
@@ -90,7 +126,10 @@ function createPluginsRouter() {
90
126
  router.delete('/:name', async (req, res) => {
91
127
  try {
92
128
  const { project, broadcast } = ctx(req);
93
- await (0, manager_1.getPluginManager)().uninstall(pluginRoot(project), project.id, req.params.name, broadcast, project.provider, project.slug);
129
+ const provider = requestedProvider(req, res, project);
130
+ if (!provider)
131
+ return;
132
+ await (0, manager_1.getPluginManager)().uninstall(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.slug, project.provider);
94
133
  res.status(200).json({ ok: true });
95
134
  }
96
135
  catch (err) {
@@ -182,7 +221,10 @@ function createPluginsRouter() {
182
221
  router.post('/:name/activate', async (req, res) => {
183
222
  try {
184
223
  const { project, broadcast } = ctx(req);
185
- await (0, manager_1.getPluginManager)().setActive(pluginRoot(project), project.id, req.params.name, true, broadcast, project.provider);
224
+ const provider = requestedProvider(req, res, project);
225
+ if (!provider)
226
+ return;
227
+ await (0, manager_1.getPluginManager)().setActive(pluginRoot(project), project.id, req.params.name, true, broadcast, provider, project.slug, project.provider);
186
228
  res.json({ ok: true });
187
229
  }
188
230
  catch (err) {
@@ -193,7 +235,10 @@ function createPluginsRouter() {
193
235
  router.post('/:name/deactivate', async (req, res) => {
194
236
  try {
195
237
  const { project, broadcast } = ctx(req);
196
- await (0, manager_1.getPluginManager)().setActive(pluginRoot(project), project.id, req.params.name, false, broadcast, project.provider);
238
+ const provider = requestedProvider(req, res, project);
239
+ if (!provider)
240
+ return;
241
+ await (0, manager_1.getPluginManager)().setActive(pluginRoot(project), project.id, req.params.name, false, broadcast, provider, project.slug, project.provider);
197
242
  res.json({ ok: true });
198
243
  }
199
244
  catch (err) {
@@ -204,7 +249,10 @@ function createPluginsRouter() {
204
249
  router.post('/:name/update', async (req, res) => {
205
250
  try {
206
251
  const { project, broadcast } = ctx(req);
207
- await (0, manager_1.getPluginManager)().updateMcpEntry(pluginRoot(project), project.id, req.params.name, broadcast, project.provider);
252
+ const provider = requestedProvider(req, res, project);
253
+ if (!provider)
254
+ return;
255
+ await (0, manager_1.getPluginManager)().updateMcpEntry(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.slug, project.provider);
208
256
  res.json({ ok: true });
209
257
  }
210
258
  catch (err) {
@@ -215,7 +263,10 @@ function createPluginsRouter() {
215
263
  router.get('/:name/health', async (req, res) => {
216
264
  try {
217
265
  const { project, broadcast } = ctx(req);
218
- const result = await (0, manager_1.getPluginManager)().verify(pluginRoot(project), project.id, req.params.name, broadcast);
266
+ const provider = requestedProvider(req, res, project);
267
+ if (!provider)
268
+ return;
269
+ const result = await (0, manager_1.getPluginManager)().verify(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.provider, project.slug);
219
270
  res.json(result);
220
271
  }
221
272
  catch (err) {