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
@@ -1,6 +1,6 @@
1
1
  # Tracking cost
2
2
 
3
- specrails-desktop records every AI CLI invocation it spawns — Claude, Codex, and Gemini — and surfaces the totals on one Analytics page per project. This guide walks through what's tracked, what's not, and how to read the dashboard.
3
+ specrails-desktop records AI CLI invocations across Claude, Codex, Gemini, and Kimi and surfaces the available metrics on one Analytics page per project. This guide walks through what's tracked, what's unavailable, and how to read the dashboard.
4
4
 
5
5
  ## What gets tracked
6
6
 
@@ -15,7 +15,17 @@ Six surfaces, all per-project:
15
15
  | **`smash`** | SMASH runs that break an epic spec into sub-specs |
16
16
  | **`file-summary`** | Code-explorer AI summaries of individual files |
17
17
 
18
- Each invocation row carries: provider (Claude, Codex, or Gemini), model, status, started/finished timestamps, duration (wall clock + API-only), tokens (in / out / cache read / cache create), total USD cost, turn count, and — when applicable — the ticket and conversation IDs it touched.
18
+ Each invocation row carries the provider, model, status, timestamps, duration,
19
+ and relevant ticket/conversation IDs. Token, USD-cost, and turn fields are
20
+ nullable because not every CLI reports them; Kimi leaves those values
21
+ unavailable rather than writing zero.
22
+
23
+ The surface list is app-wide, not a promise that every provider can spawn
24
+ every row type. Kimi records its agentic chats/Explore/rails/loops, but Quick
25
+ Spec, AI Edit, Contract Refine, SMASH/Re-SMASH, file summaries, construction
26
+ story, AI auto-title, Project Builder blueprint/milestone generation, Loop
27
+ Decider, and Agent Studio automation fail before spawn. Those rejected
28
+ requests create no invocation row; AI auto-title uses a deterministic fallback.
19
29
 
20
30
  > Cost averages exclude `failed`/`aborted` rows, but those rows still count toward the total run count and the failure rate.
21
31
 
@@ -25,6 +35,9 @@ Whether a cost figure is exact depends on the provider's CLI, not on which provi
25
35
 
26
36
  - **Claude cost is provider-billed and authoritative** — the figure comes straight from the CLI's own usage report.
27
37
  - **Codex and Gemini do not report cost natively**, so the app **estimates** their cost from a local rate-card (`server/pricing.ts`) using the captured token counts. Estimated rows are flagged: they render with a `~` tilde in the raw table (hover for the tooltip — *"Estimated from local pricing table — this provider does not report cost natively"*) and feed an "includes ~$X estimated" footnote in the Hero.
38
+ - **Kimi reports neither token counts nor a native USD-cost envelope** in its
39
+ stream. Specrails does not invent an estimate: cost and token cells stay
40
+ unavailable.
28
41
 
29
42
  On multi-provider projects, a **Provider breakdown** card splits spend across the project's installed engines so you can see authoritative vs estimated at a glance.
30
43
 
@@ -32,10 +45,12 @@ On multi-provider projects, a **Provider breakdown** card splits spend across th
32
45
 
33
46
  ## What's NOT tracked (intentionally)
34
47
 
35
- - **Sidebar chat** — the general-purpose chat panel in the right sidebar. It spawns an AI process but isn't pipeline work, so the app excludes it from analytics by design.
48
+ - **Sidebar chat** — the general-purpose chat panel in the right sidebar. It spawns an AI process, including `kimi -p` when Kimi is selected, but isn't pipeline work, so the app excludes it from analytics by design.
36
49
  - **Setup wizard** — the install/enrich flow when you add a project. It *does* spawn an AI CLI (a genuine model invocation), but it's an interactive one-time wizard rather than a repeatable pipeline job, so it's deliberately left uninstrumented.
37
50
 
38
- If you want the absolute total of what an engine has cost you, your provider's own console is the source of truth — the Anthropic console for Claude, the OpenAI dashboard for Codex, and Google AI Studio / Cloud billing for Gemini.
51
+ If you want the absolute total of what an engine has cost you, your provider's
52
+ own console is the source of truth. This is especially important for Kimi,
53
+ whose CLI stream provides no billable usage envelope to Desktop.
39
54
 
40
55
  ## The Analytics page
41
56
 
@@ -45,7 +60,7 @@ Open **Analytics** from the project right sidebar.
45
60
 
46
61
  - **Period** — `7d`, `30d`, `90d`, or `All`. (There's no 24-hour or custom-range option here — the custom calendar range lives on Desktop Analytics, below.)
47
62
  - **Surface** — chips for `All` plus each of the six surfaces (Jobs, Explore, Quick, Refine, SMASH, File summaries). All are included by default; toggle chips to narrow the view.
48
- - **Engine** — one chip per installed provider (Claude, Codex, Gemini) plus `All`. These appear **only on multi-provider projects** (more than one engine installed) and let you filter spend by engine.
63
+ - **Engine** — one chip per installed provider plus `All`. These appear **only on multi-provider projects** and let you filter activity by engine.
49
64
 
50
65
  The period and surface filters are URL-synced, so you can share or bookmark a view.
51
66
 
@@ -62,7 +77,10 @@ When the project has zero invocations in the period (e.g. you just started), the
62
77
 
63
78
  ### Provider breakdown
64
79
 
65
- On multi-provider projects, a dedicated card splits total spend across the project's installed engines (Claude, Codex, Gemini) — it's data-driven, so it renders for any combination of more than one provider. Each engine's row marks an all-estimated total with a `~` tilde. It's hidden on single-provider projects.
80
+ On multi-provider projects, a dedicated card splits available spend across the
81
+ project's installed engines. It is data-driven, so Kimi appears even though its
82
+ cost is unavailable. Estimated Codex/Gemini totals carry a `~` tilde. The card
83
+ is hidden on single-provider projects.
66
84
 
67
85
  ### Daily stacked timeline
68
86
 
@@ -159,3 +177,4 @@ For the cross-project view, open **Analytics** from the Arc sidebar on the left.
159
177
  - [Creating specs](creating-specs.md) — every spec you create adds rows to your analytics.
160
178
  - [Using Codex](codex.md) — how cost works when you run a project on Codex (estimated, ~ tilde).
161
179
  - [Using Gemini](gemini.md) — how cost works when you run a project on Gemini (also estimated, ~ tilde).
180
+ - [Using Kimi](kimi.md) — why Kimi duration/outcome are recorded while tokens and cost remain unavailable.
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "specrails-desktop",
3
- "version": "2.30.2",
3
+ "version": "2.31.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/fjpulidop/specrails-desktop.git"
8
8
  },
9
9
  "engines": {
10
- "node": ">=20.0.0"
10
+ "node": ">=20.19.0"
11
11
  },
12
12
  "bin": {
13
13
  "specrails-desktop": "cli/dist/specrails-desktop.js"
@@ -51,6 +51,7 @@
51
51
  "cross-spawn": "^7.0.6",
52
52
  "diff": "^9.0.0",
53
53
  "express": "^5.2.1",
54
+ "js-yaml": "4.1.1",
54
55
  "multer": "^2.2.0",
55
56
  "node-pty": "^1.0.0",
56
57
  "pdf-parse": "^2.4.5",
@@ -69,6 +70,7 @@
69
70
  "@types/cross-spawn": "^6.0.6",
70
71
  "@types/diff": "^7.0.2",
71
72
  "@types/express": "^5.0.6",
73
+ "@types/js-yaml": "^4.0.9",
72
74
  "@types/multer": "^2.1.0",
73
75
  "@types/node": "^25.5.0",
74
76
  "@types/pdf-parse": "^1.1.5",
@@ -8,8 +8,10 @@ exports.sanitizeAgentTitle = sanitizeAgentTitle;
8
8
  const crypto_1 = require("crypto");
9
9
  const readline_1 = require("readline");
10
10
  const os_1 = require("os");
11
+ const node_path_1 = __importDefault(require("node:path"));
11
12
  const tree_kill_1 = __importDefault(require("tree-kill"));
12
13
  const providers_1 = require("./providers");
14
+ const runtime_1 = require("./providers/runtime");
13
15
  const spawn_lifecycle_1 = require("./spawn-lifecycle");
14
16
  const cli_prompt_1 = require("./util/cli-prompt");
15
17
  const result_event_1 = require("./result-event");
@@ -23,6 +25,18 @@ const attachment_manager_1 = require("./attachment-manager");
23
25
  const agent_context_resolver_1 = require("./agent-context-resolver");
24
26
  const agent_store_1 = require("./agent-store");
25
27
  const explore_draft_title_1 = require("./explore-draft-title");
28
+ /**
29
+ * Providers report an expired or foreign resume token as a normalized error.
30
+ * Those errors are safe to recover from by clearing the token and retrying the
31
+ * same turn once; every other provider error remains terminal.
32
+ */
33
+ function isStaleResumeError(message) {
34
+ if (!message)
35
+ return false;
36
+ return (/no rollout found for thread id/i.test(message) ||
37
+ /unknown (?:session|thread)(?: id)?\b/i.test(message) ||
38
+ /(?:session|thread)(?: id)?\b[^\n]{0,160}\b(?:not found|does not exist)\b/i.test(message));
39
+ }
26
40
  class AgentChatManager {
27
41
  _broadcast;
28
42
  _db;
@@ -218,17 +232,20 @@ class AgentChatManager {
218
232
  // Resolve a model that is VALID for this provider. A stale model from another
219
233
  // provider (e.g. claude's "sonnet" after switching to codex) is rejected by
220
234
  // the provider — fall back to the provider's default instead of failing.
221
- const catalog = new Set(adapter.modelCatalog().map((m) => m.value));
222
235
  const requested = options.model || conversation.model;
223
- const model = requested && catalog.has(requested) ? requested : adapter.defaultModel();
224
- // Reasoning effort: stored per conversation; null = the app default
225
- // ("medium"). Passed only to providers with a per-spawn knob, and only when
226
- // the value is in the provider's catalog (a provider switch clears it, but
227
- // belt-and-braces against stale rows).
228
- const efforts = (adapter.capabilities.reasoningEfforts ?? []);
236
+ const model = requested && (0, providers_1.isModelAvailableForAdapter)(adapter, requested)
237
+ ? requested
238
+ : adapter.defaultModel();
239
+ // Reasoning effort is model-scoped. A stale value from a previous model is
240
+ // discarded and the default is selected from the effective model's exact
241
+ // catalog (K3 follows its native high default; other Kimi models expose no
242
+ // per-invocation knob).
243
+ const efforts = (0, providers_1.reasoningEffortsForModel)(adapter, model);
229
244
  const storedEffort = conversation.reasoning_effort;
230
245
  const reasoningEffort = efforts.length
231
- ? (storedEffort && efforts.includes(storedEffort) ? storedEffort : 'medium')
246
+ ? (storedEffort && efforts.includes(storedEffort)
247
+ ? storedEffort
248
+ : (0, providers_1.defaultReasoningEffortForModel)(adapter, model))
232
249
  : undefined;
233
250
  // Resolve attachments (conversation-keyed) into extracted text blocks +
234
251
  // absolute image paths. Extraction failure degrades to a text-only turn.
@@ -286,6 +303,9 @@ class AgentChatManager {
286
303
  const systemPrompt = hasAttachments
287
304
  ? `${agent_operator_prompt_1.OPERATOR_SYSTEM_PROMPT}\n\n${attachment_manager_1.USER_ATTACHMENT_SYSTEM_NOTE}`
288
305
  : agent_operator_prompt_1.OPERATOR_SYSTEM_PROMPT;
306
+ const effectivePrompt = adapter.capabilities.systemPromptArg
307
+ ? prompt
308
+ : `${systemPrompt}\n\n---\n\n${prompt}`;
289
309
  // Only pass native image paths to providers that can vision-load them (codex
290
310
  // `--image`); claude/gemini already have the `@path` ref folded into prompt.
291
311
  const spawnImagePaths = adapter.capabilities.supportsImageInput ? imagePaths : undefined;
@@ -300,7 +320,10 @@ class AgentChatManager {
300
320
  // / `.gemini/settings.json` and launch with the other's capability.
301
321
  // Claude and Codex keep their historical global cwd and explicit MCP
302
322
  // registration mechanisms unchanged.
303
- const cwd = adapter.id === 'gemini'
323
+ const projectMcpPath = adapter.projectMcpPath?.('.');
324
+ const needsConversationMcpCwd = !!projectMcpPath &&
325
+ node_path_1.default.dirname(projectMcpPath) !== '.';
326
+ const cwd = needsConversationMcpCwd
304
327
  ? (0, agent_cwd_manager_1.ensureAgentConversationCwd)(conversationId)
305
328
  : (0, agent_cwd_manager_1.ensureAgentCwd)();
306
329
  let mcpArgs = [];
@@ -329,21 +352,22 @@ class AgentChatManager {
329
352
  let capturedError = null;
330
353
  console.log(`[agent-chat] turn start conv=${conversationId} provider=${adapter.id} binary=${adapter.binary} ` +
331
354
  `action=${action} model=${model} cwd=${cwd} mcp=${mcpArgs.length ? 'mcp-config' : Object.keys(mcpEnv).join(',') || 'none'}`);
355
+ const buildOpts = {
356
+ prompt: effectivePrompt,
357
+ systemPrompt: adapter.capabilities.systemPromptArg ? systemPrompt : undefined,
358
+ model,
359
+ sessionId: useResume ? conversation.session_id ?? undefined : undefined,
360
+ extraArgs: mcpArgs,
361
+ imagePaths: spawnImagePaths,
362
+ reasoning_effort: reasoningEffort,
363
+ };
332
364
  const invocation = this._awaitWhileLive((0, spawn_lifecycle_1.runAiCliInvocation)({
333
365
  adapter,
334
366
  action,
335
367
  cwd,
336
- env: { ...process.env, ...mcpEnv },
368
+ env: (0, runtime_1.buildProviderEnv)(adapter, buildOpts, { ...process.env, ...mcpEnv }),
337
369
  spawn: this._spawnOwned.bind(this),
338
- buildOpts: {
339
- prompt,
340
- systemPrompt: adapter.capabilities.systemPromptArg ? systemPrompt : undefined,
341
- model,
342
- sessionId: useResume ? conversation.session_id ?? undefined : undefined,
343
- extraArgs: mcpArgs,
344
- imagePaths: spawnImagePaths,
345
- reasoning_effort: reasoningEffort,
346
- },
370
+ buildOpts,
347
371
  onSpawn: (child) => {
348
372
  if (this._disposed) {
349
373
  this._terminate(child);
@@ -464,7 +488,10 @@ class AgentChatManager {
464
488
  // Auto-heal a stale/foreign session: a resume that produced no text (e.g. a
465
489
  // provider switch leaving another provider's session id, or codex
466
490
  // "no rollout found for thread id") retries once as a fresh turn.
467
- if (canResume && !r.spawnFailed && !r.text) {
491
+ if (canResume &&
492
+ !r.spawnFailed &&
493
+ !r.text &&
494
+ (!r.error || isStaleResumeError(r.error))) {
468
495
  console.log(`[agent-chat] resume produced no text — retrying fresh conv=${conversationId}`);
469
496
  (0, agent_store_1.updateAgentConversation)(this._db, conversationId, { session_id: null });
470
497
  r = await invoke(false);
@@ -485,6 +512,17 @@ class AgentChatManager {
485
512
  record(r, 'failed');
486
513
  return;
487
514
  }
515
+ // A normalized provider error is authoritative even when the CLI exits
516
+ // zero or streamed partial text before failing.
517
+ if (r.error || r.code !== 0) {
518
+ persistSession(null);
519
+ const reason = r.error ||
520
+ (r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
521
+ `${adapter.binary} exited with code ${r.code ?? 'unknown'}`;
522
+ this._emitError(conversationId, reason);
523
+ record(r, 'failed');
524
+ return;
525
+ }
488
526
  if (r.text) {
489
527
  (0, agent_store_1.addAgentMessage)(this._db, { conversationId, role: 'assistant', content: r.text });
490
528
  persistSession(r.sessionId);
@@ -499,9 +537,8 @@ class AgentChatManager {
499
537
  // Failure: reset the session so the NEXT turn starts fresh, and surface the
500
538
  // real reason instead of silently doing nothing.
501
539
  persistSession(null);
502
- const reason = r.error ||
503
- (r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
504
- (r.code !== 0 ? `${adapter.binary} exited with code ${r.code}` : 'The agent returned no output.');
540
+ const reason = (r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
541
+ 'The agent returned no output.';
505
542
  this._emitError(conversationId, reason);
506
543
  record(r, 'failed');
507
544
  }
@@ -523,8 +560,10 @@ class AgentChatManager {
523
560
  if (this._disposed)
524
561
  return;
525
562
  try {
563
+ const finishedAt = new Date().toISOString();
526
564
  const { result, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, outcome.events, {
527
565
  fallbackModel: model,
566
+ durationMs: Math.max(0, Date.parse(finishedAt) - Date.parse(outcome.startedAt)),
528
567
  });
529
568
  (0, desktop_db_1.recordAgentInvocation)(this._db, {
530
569
  id: (0, crypto_1.randomUUID)(),
@@ -533,7 +572,7 @@ class AgentChatManager {
533
572
  provider: adapter.id,
534
573
  status,
535
574
  started_at: outcome.startedAt,
536
- finished_at: new Date().toISOString(),
575
+ finished_at: finishedAt,
537
576
  total_cost_usd_estimated: estimated,
538
577
  ...result,
539
578
  });
@@ -614,13 +653,17 @@ class AgentChatManager {
614
653
  try {
615
654
  const conversationId = conversation.id;
616
655
  const adapter = (0, providers_1.getAdapter)(conversation.provider);
656
+ const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter);
657
+ if (!toolPolicy)
658
+ return;
617
659
  const model = adapter.defaultModel();
618
660
  const prompt = 'Generate a concise 3-6 word title for this conversation. ' +
619
661
  'Output ONLY the title text — no quotes, no punctuation, no markdown, no preamble.\n\n' +
620
662
  `User: ${firstUserMsg.slice(0, 240)}\nAssistant: ${firstResponse.slice(0, 320)}`;
621
- const args = adapter.buildArgs('auto-title', { prompt, model });
663
+ const titleOptions = { prompt, model, toolPolicy };
664
+ const args = adapter.buildArgs('auto-title', titleOptions);
622
665
  const child = this._spawnOwned(adapter.binary, args, {
623
- env: process.env,
666
+ env: (0, runtime_1.buildProviderEnv)(adapter, titleOptions),
624
667
  stdio: ['ignore', 'pipe', 'pipe'],
625
668
  cwd: (0, os_1.tmpdir)(),
626
669
  });
@@ -633,12 +676,11 @@ class AgentChatManager {
633
676
  reader.on('line', (line) => {
634
677
  if (this._disposed)
635
678
  return;
636
- const ev = adapter.parseStreamLine(line);
637
- if (!ev)
638
- return;
639
- events.push(ev);
640
- if (ev.kind === 'text-delta')
641
- raw += ev.text;
679
+ for (const ev of (0, runtime_1.parseStreamEvents)(adapter, line)) {
680
+ events.push(ev);
681
+ if (ev.kind === 'text-delta')
682
+ raw += ev.text;
683
+ }
642
684
  });
643
685
  child.on('error', () => {
644
686
  this._auxProcesses.delete(child);
@@ -120,24 +120,30 @@ function createAgentChatRouter(deps) {
120
120
  router.get('/models', (req, res) => {
121
121
  const provider = validProvider(req.query.provider) ?? 'claude';
122
122
  const adapter = (0, providers_1.getAdapter)(provider);
123
+ const requestedModel = (0, providers_1.isModelAvailableForAdapter)(adapter, req.query.model)
124
+ ? req.query.model
125
+ : null;
126
+ const model = requestedModel ?? adapter.defaultModel();
123
127
  res.json({
124
128
  provider,
129
+ model,
125
130
  models: adapter.modelCatalog(),
131
+ customModelAliases: adapter.capabilities.customModelAliases === true,
126
132
  // The composer gates the image affordance on this (design D22: capability,
127
133
  // never provider id — gemini stays false until live-verified).
128
134
  supportsImageInput: adapter.capabilities.supportsImageInput === true,
129
135
  // Per-provider reasoning-effort tiers (ascending). Empty ⇒ no selector
130
136
  // (gemini has no per-spawn knob).
131
- efforts: adapter.capabilities.reasoningEfforts ?? [],
137
+ efforts: (0, providers_1.reasoningEffortsForModel)(adapter, model),
132
138
  });
133
139
  });
134
- /** Validate a requested reasoning effort against a provider's catalog. */
135
- const validEffort = (provider, value) => {
140
+ /** Validate a requested effort against the effective model's exact catalog. */
141
+ const validEffort = (provider, model, value) => {
136
142
  if (value === null)
137
143
  return null;
138
144
  if (typeof value !== 'string')
139
145
  return undefined;
140
- const efforts = (0, providers_1.getAdapter)(provider).capabilities.reasoningEfforts ?? [];
146
+ const efforts = (0, providers_1.reasoningEffortsForModel)((0, providers_1.getAdapter)(provider), model);
141
147
  return efforts.includes(value) ? value : undefined;
142
148
  };
143
149
  router.get('/conversations', (_req, res) => {
@@ -154,13 +160,20 @@ function createAgentChatRouter(deps) {
154
160
  }
155
161
  provider = v;
156
162
  }
163
+ const adapter = (0, providers_1.getAdapter)(provider);
164
+ const requestedModel = body.model == null ? null : body.model;
165
+ if (requestedModel !== null && !(0, providers_1.isModelAvailableForAdapter)(adapter, requestedModel)) {
166
+ res.status(400).json({ error: 'Model not available for this provider' });
167
+ return;
168
+ }
169
+ const effectiveModel = requestedModel ?? adapter.defaultModel();
157
170
  const conversation = (0, agent_store_1.createAgentConversation)(desktopDb, {
158
171
  provider,
159
- model: typeof body.model === 'string' ? body.model : null,
172
+ model: requestedModel,
160
173
  pinnedProjectId: typeof body.pinnedProjectId === 'string' ? body.pinnedProjectId : null,
161
174
  tierLevel: body.tierLevel !== undefined ? (0, agent_tier_1.normalizeLevel)(body.tierLevel) : 0,
162
- // Off-catalog values fall back to null (= app default "medium").
163
- reasoningEffort: validEffort(provider, body.reasoningEffort) ?? null,
175
+ // Off-catalog values fall back to null (= no provider-specific override).
176
+ reasoningEffort: validEffort(provider, effectiveModel, body.reasoningEffort) ?? null,
164
177
  });
165
178
  res.status(201).json({ conversation });
166
179
  });
@@ -206,31 +219,41 @@ function createAgentChatRouter(deps) {
206
219
  }
207
220
  }
208
221
  // Explicit model pick — validated against the (new or current) provider's catalog.
209
- if (body.model !== undefined && patch.model === undefined) {
222
+ if (body.model !== undefined) {
223
+ const effectiveProvider = patch.provider ?? conversation.provider;
210
224
  if (body.model === null) {
211
225
  patch.model = null;
212
226
  }
213
227
  else if (typeof body.model === 'string') {
214
- const effectiveProvider = patch.provider ?? conversation.provider;
215
- const valid = new Set((0, providers_1.getAdapter)(effectiveProvider).modelCatalog().map((m) => m.value));
216
- if (!valid.has(body.model)) {
228
+ if (!(0, providers_1.isModelAvailableForAdapter)((0, providers_1.getAdapter)(effectiveProvider), body.model)) {
217
229
  res.status(400).json({ error: 'Model not available for this provider' });
218
230
  return;
219
231
  }
220
232
  patch.model = body.model;
221
233
  }
222
234
  }
223
- // Explicit effort pick — validated against the (new or current) provider's
224
- // effort catalog; null resets to the app default ("medium").
225
- if (body.reasoningEffort !== undefined && patch.reasoning_effort === undefined) {
226
- const effectiveProvider = patch.provider ?? conversation.provider;
227
- const v = validEffort(effectiveProvider, body.reasoningEffort);
235
+ const effectiveProvider = patch.provider ?? conversation.provider;
236
+ const adapter = (0, providers_1.getAdapter)(effectiveProvider);
237
+ const effectiveModel = typeof patch.model === 'string'
238
+ ? patch.model
239
+ : patch.model === null
240
+ ? adapter.defaultModel()
241
+ : conversation.model ?? adapter.defaultModel();
242
+ // Explicit effort pick — validated against the effective model. A model
243
+ // change without an effort pick clears a now-incompatible persisted value.
244
+ if (body.reasoningEffort !== undefined) {
245
+ const v = validEffort(effectiveProvider, effectiveModel, body.reasoningEffort);
228
246
  if (v === undefined) {
229
- res.status(400).json({ error: 'Effort not available for this provider' });
247
+ res.status(400).json({ error: 'Effort not available for this provider and model' });
230
248
  return;
231
249
  }
232
250
  patch.reasoning_effort = v;
233
251
  }
252
+ else if (body.model !== undefined
253
+ && conversation.reasoning_effort
254
+ && validEffort(effectiveProvider, effectiveModel, conversation.reasoning_effort) === undefined) {
255
+ patch.reasoning_effort = null;
256
+ }
234
257
  res.json({ conversation: (0, agent_store_1.updateAgentConversation)(desktopDb, conversation.id, patch) });
235
258
  });
236
259
  router.delete('/conversations/:id', (req, res) => {
@@ -16,10 +16,10 @@ const agent_operator_prompt_1 = require("./agent-operator-prompt");
16
16
  //
17
17
  // The agent chat spawns the AI CLI from an app-owned cwd (NOT a project path), so
18
18
  // no project's CLAUDE.md is auto-loaded and the agent starts with a focused
19
- // "operator" stance. Claude/Codex retain the original app-global cwd. Gemini
20
- // gets a per-conversation child cwd because it discovers project MCP settings
21
- // from `<cwd>/.gemini/settings.json`; sharing that file would let concurrent
22
- // conversations overwrite each other's capability-file reference.
19
+ // "operator" stance. Claude/Codex retain the original app-global cwd. Providers
20
+ // whose MCP config is cwd-discovered under a nested project path (Gemini/Kimi)
21
+ // get a per-conversation child cwd so concurrent turns cannot overwrite each
22
+ // other's capability-file reference.
23
23
  function homeDir() {
24
24
  return process.env.SPECRAILS_REGISTRY_HOME || os_1.default.homedir();
25
25
  }
@@ -65,6 +65,14 @@ function ensureAgentCwd() {
65
65
  fs_1.default.rmdirSync(path_1.default.join(dir, '.gemini'));
66
66
  }
67
67
  catch { /* non-empty / absent */ }
68
+ try {
69
+ fs_1.default.unlinkSync(path_1.default.join(dir, '.kimi-code', 'mcp.json'));
70
+ }
71
+ catch { /* absent */ }
72
+ try {
73
+ fs_1.default.rmdirSync(path_1.default.join(dir, '.kimi-code'));
74
+ }
75
+ catch { /* non-empty / absent */ }
68
76
  return dir;
69
77
  }
70
78
  /** Path for provider state that must not be shared across agent conversations. */
@@ -75,9 +83,8 @@ function agentConversationCwdPath(conversationId) {
75
83
  return path_1.default.join(agentCwdPath(), 'conversations', conversationId);
76
84
  }
77
85
  /**
78
- * Materialise an isolated agent cwd for one conversation. Gemini uses this so
79
- * its cwd-discovered `.mcp.json` and `.gemini/settings.json` can never be
80
- * overwritten by a concurrent turn belonging to another conversation.
86
+ * Materialise an isolated agent cwd for one conversation. Cwd-discovered
87
+ * provider MCP files can never be overwritten by another conversation.
81
88
  */
82
89
  function ensureAgentConversationCwd(conversationId) {
83
90
  return ensureCwd(agentConversationCwdPath(conversationId));