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
@@ -8,12 +8,12 @@ exports.CORE_PACKAGE_SPEC = void 0;
8
8
  * minute it is published — adopting a new major is a deliberate one-line
9
9
  * bump here, shipped through the app's own release pipeline.
10
10
  *
11
- * Floor bumped to 4.8.0 — the version that ships the Gemini provider target
12
- * (`.gemini/` commands + agents). It also changes the `npx` package-spec string,
11
+ * Floor bumped to 4.12.0 — the version that ships the Kimi provider target
12
+ * (`.kimi-code/` skills + roles). It also changes the `npx` package-spec string,
13
13
  * which invalidates any stale `_npx` exec cache that npx would otherwise reuse
14
14
  * for the old `^4.6.0` range (so users actually resolve the newer core).
15
15
  *
16
16
  * `SPECRAILS_CORE_BIN` remains the escape hatch for local/linked builds
17
17
  * (see getCoreCommand in setup-manager.ts).
18
18
  */
19
- exports.CORE_PACKAGE_SPEC = 'specrails-core@^4.8.0';
19
+ exports.CORE_PACKAGE_SPEC = 'specrails-core@^4.12.0';
@@ -116,7 +116,13 @@ class CoreUpdateManager {
116
116
  }
117
117
  this.updating = true;
118
118
  this.emit('downloading', { version: requested });
119
- const tmp = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'core-update-'));
119
+ // realpath the tmp root: on macOS os.tmpdir() is a symlinked path
120
+ // (/var/folders → /private/var/folders). The staged core's cli.js has an
121
+ // auto-run guard comparing import.meta.url (realpathed by Node's ESM
122
+ // loader) against process.argv[1] (the literal spawn arg) — a symlinked
123
+ // staging path makes them differ, so main() never runs and every
124
+ // install-framework/swap-current child exits 0 as a silent no-op.
125
+ const tmp = fs_1.default.mkdtempSync(path_1.default.join(realTmpDir(), 'core-update-'));
120
126
  try {
121
127
  this.npmInstallFn(`${exports.CORE_PACKAGE}@${requested}`, tmp);
122
128
  const coreRoot = path_1.default.join(tmp, 'node_modules', exports.CORE_PACKAGE);
@@ -187,6 +193,16 @@ function uniqueProviders(values) {
187
193
  const out = Array.from(new Set(values.filter((v) => typeof v === 'string' && v.length > 0)));
188
194
  return out.length > 0 ? out : ['claude'];
189
195
  }
196
+ /** os.tmpdir() with symlinks resolved (macOS /var/folders → /private/var/folders). */
197
+ function realTmpDir() {
198
+ const dir = os_1.default.tmpdir();
199
+ try {
200
+ return fs_1.default.realpathSync(dir);
201
+ }
202
+ catch {
203
+ return dir;
204
+ }
205
+ }
190
206
  /** GET the latest published version from the npm registry (no npm binary needed). */
191
207
  async function fetchLatestFromRegistry() {
192
208
  const controller = new AbortController();
package/server/dist/db.js CHANGED
@@ -1426,6 +1426,44 @@ const MIGRATIONS = [
1426
1426
  db.exec(`ALTER TABLE rail_pr_deliveries ADD COLUMN safety_archives TEXT NOT NULL DEFAULT '[]'`);
1427
1427
  }
1428
1428
  },
1429
+ // Migration 55: Agent Studio history belongs to a provider-native role
1430
+ // catalog. The same logical custom role id can validly exist for Claude and
1431
+ // Kimi in one project; keying history only by agent_name mixed bodies and
1432
+ // version counters across those catalogs. Legacy rows predate provider-aware
1433
+ // Studio and therefore belong to Claude.
1434
+ (db) => {
1435
+ const versionCols = new Set(db.prepare(`PRAGMA table_info(agent_versions)`).all()
1436
+ .map((row) => row.name));
1437
+ if (!versionCols.has('provider')) {
1438
+ db.exec(`
1439
+ ALTER TABLE agent_versions RENAME TO agent_versions_v54;
1440
+ CREATE TABLE agent_versions (
1441
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1442
+ provider TEXT NOT NULL DEFAULT 'claude',
1443
+ agent_name TEXT NOT NULL,
1444
+ version INTEGER NOT NULL,
1445
+ body TEXT NOT NULL,
1446
+ created_at INTEGER NOT NULL,
1447
+ UNIQUE (provider, agent_name, version)
1448
+ );
1449
+ INSERT INTO agent_versions (id, provider, agent_name, version, body, created_at)
1450
+ SELECT id, 'claude', agent_name, version, body, created_at
1451
+ FROM agent_versions_v54;
1452
+ DROP TABLE agent_versions_v54;
1453
+ CREATE INDEX idx_agent_versions_provider_name
1454
+ ON agent_versions(provider, agent_name);
1455
+ `);
1456
+ }
1457
+ const testCols = new Set(db.prepare(`PRAGMA table_info(agent_tests)`).all()
1458
+ .map((row) => row.name));
1459
+ if (!testCols.has('provider')) {
1460
+ db.exec(`ALTER TABLE agent_tests ADD COLUMN provider TEXT NOT NULL DEFAULT 'claude'`);
1461
+ }
1462
+ db.exec(`
1463
+ CREATE INDEX IF NOT EXISTS idx_agent_tests_provider_name
1464
+ ON agent_tests(provider, agent_name)
1465
+ `);
1466
+ },
1429
1467
  ];
1430
1468
  function applyMigrations(db) {
1431
1469
  // Ensure the migrations table exists (migration 1 creates it, but we need
@@ -1624,7 +1662,12 @@ function listJobs(db, opts) {
1624
1662
  }
1625
1663
  function getJob(db, jobId) {
1626
1664
  return db
1627
- .prepare('SELECT * FROM jobs WHERE id = ?')
1665
+ .prepare(`
1666
+ SELECT jobs.*, jp.profile_name AS profile_name
1667
+ FROM jobs
1668
+ LEFT JOIN job_profiles jp ON jp.job_id = jobs.id
1669
+ WHERE jobs.id = ?
1670
+ `)
1628
1671
  .get(jobId);
1629
1672
  }
1630
1673
  function getJobEvents(db, jobId) {
@@ -1884,11 +1927,19 @@ function getStats(db) {
1884
1927
  const costSum = `COALESCE(SUM(total_cost_usd), 0)`;
1885
1928
  const estSum = `COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0)`;
1886
1929
  const costRow = db.prepare(`
1887
- SELECT ${costSum} as totalCostUsd, ${estSum} as estimatedCostUsd
1930
+ SELECT
1931
+ ${costSum} as totalCostUsd,
1932
+ ${estSum} as estimatedCostUsd,
1933
+ COUNT(total_cost_usd) as pricedRuns,
1934
+ SUM(CASE WHEN total_cost_usd IS NULL THEN 1 ELSE 0 END) as unpricedRuns
1888
1935
  FROM ai_invocations
1889
1936
  `).get();
1890
1937
  const costTodayRow = db.prepare(`
1891
- SELECT ${costSum} as costToday, ${estSum} as estimatedCostToday
1938
+ SELECT
1939
+ ${costSum} as costToday,
1940
+ ${estSum} as estimatedCostToday,
1941
+ COUNT(total_cost_usd) as pricedTodayRuns,
1942
+ SUM(CASE WHEN total_cost_usd IS NULL THEN 1 ELSE 0 END) as unpricedTodayRuns
1892
1943
  FROM ai_invocations
1893
1944
  WHERE strftime('%Y-%m-%d', started_at) = ?
1894
1945
  `).get(today);
@@ -1900,14 +1951,18 @@ function getStats(db) {
1900
1951
  costToday: costTodayRow.costToday,
1901
1952
  estimatedCostUsd: costRow.estimatedCostUsd,
1902
1953
  estimatedCostToday: costTodayRow.estimatedCostToday,
1954
+ pricedRuns: costRow.pricedRuns,
1955
+ unpricedRuns: costRow.unpricedRuns ?? 0,
1956
+ pricedTodayRuns: costTodayRow.pricedTodayRuns,
1957
+ unpricedTodayRuns: costTodayRow.unpricedTodayRuns ?? 0,
1903
1958
  avgDurationMs: totalRow.avgDurationMs,
1904
1959
  };
1905
1960
  }
1906
1961
  // ─── Project settings ─────────────────────────────────────────────────────────
1907
1962
  /**
1908
- * Default pre-prompt used by Freestyle (Claude-only rails) when the project
1963
+ * Default pre-prompt used by provider-capable Freestyle rails when the project
1909
1964
  * has no per-project override. Freestyle skips the OpenSpec pipeline entirely:
1910
- * it hands Claude the spec text plus this instruction and lets it work
1965
+ * it hands the selected autonomous provider the spec text plus this instruction and lets it work
1911
1966
  * autonomously end-to-end.
1912
1967
  */
1913
1968
  exports.DEFAULT_FREESTYLE_PRE_PROMPT = [
@@ -55,7 +55,9 @@ function queryProjectCost(db, clause, params) {
55
55
  return db.prepare(`
56
56
  SELECT
57
57
  COALESCE(SUM(total_cost_usd), 0) as totalCostUsd,
58
- COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) as estimatedCostUsd
58
+ COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) as estimatedCostUsd,
59
+ COUNT(total_cost_usd) as pricedRuns,
60
+ SUM(CASE WHEN total_cost_usd IS NULL THEN 1 ELSE 0 END) as unpricedRuns
59
61
  FROM ai_invocations ${clause}
60
62
  `).get(...params);
61
63
  }
@@ -76,6 +78,8 @@ function queryProjectKpi(db, clause, params) {
76
78
  return {
77
79
  totalCostUsd: cost.totalCostUsd,
78
80
  estimatedCostUsd: cost.estimatedCostUsd,
81
+ pricedRuns: cost.pricedRuns ?? 0,
82
+ unpricedRuns: cost.unpricedRuns ?? 0,
79
83
  totalJobs: counts.totalJobs,
80
84
  successCount: counts.successCount ?? 0,
81
85
  avgDurationMs: counts.avgDurationMs,
@@ -110,7 +114,8 @@ function queryProjectTimeline(db, clause, params) {
110
114
  SELECT
111
115
  strftime('%Y-%m-%d', started_at) as date,
112
116
  COALESCE(SUM(total_cost_usd), 0) as costUsd,
113
- COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) as estimatedCostUsd
117
+ COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) as estimatedCostUsd,
118
+ SUM(CASE WHEN total_cost_usd IS NULL THEN 1 ELSE 0 END) as unpricedCount
114
119
  FROM ai_invocations ${clause}
115
120
  GROUP BY date
116
121
  ORDER BY date ASC
@@ -127,10 +132,14 @@ function getDesktopAnalytics(registry, opts) {
127
132
  const contexts = registry.listContexts();
128
133
  let totalCostUsd = 0;
129
134
  let estimatedCostUsd = 0;
135
+ let pricedRuns = 0;
136
+ let unpricedRuns = 0;
130
137
  let totalJobs = 0;
131
138
  let totalSuccess = 0;
132
139
  let costToday = 0;
133
140
  let estimatedCostToday = 0;
141
+ let pricedTodayRuns = 0;
142
+ let unpricedTodayRuns = 0;
134
143
  let jobsToday = 0;
135
144
  const projectBreakdown = [];
136
145
  const timelineMap = new Map();
@@ -141,24 +150,31 @@ function getDesktopAnalytics(registry, opts) {
141
150
  const timeline = queryProjectTimeline(ctx.db, clause, params);
142
151
  totalCostUsd += kpi.totalCostUsd;
143
152
  estimatedCostUsd += kpi.estimatedCostUsd;
153
+ pricedRuns += kpi.pricedRuns;
154
+ unpricedRuns += kpi.unpricedRuns;
144
155
  totalJobs += kpi.totalJobs;
145
156
  totalSuccess += kpi.successCount;
146
157
  costToday += todayKpi.totalCostUsd;
147
158
  estimatedCostToday += todayKpi.estimatedCostUsd;
159
+ pricedTodayRuns += todayKpi.pricedRuns;
160
+ unpricedTodayRuns += todayKpi.unpricedRuns;
148
161
  jobsToday += todayKpi.totalJobs;
149
162
  projectBreakdown.push({
150
163
  projectId: ctx.project.id,
151
164
  projectName: ctx.project.name,
152
165
  totalCostUsd: kpi.totalCostUsd,
153
166
  estimatedCostUsd: kpi.estimatedCostUsd,
167
+ pricedRuns: kpi.pricedRuns,
168
+ unpricedRuns: kpi.unpricedRuns,
154
169
  totalJobs: kpi.totalJobs,
155
170
  successRate: kpi.totalJobs > 0 ? kpi.successCount / kpi.totalJobs : 0,
156
171
  avgDurationMs: kpi.avgDurationMs,
157
172
  });
158
173
  for (const row of timeline) {
159
- const acc = timelineMap.get(row.date) ?? { costUsd: 0, estimatedCostUsd: 0 };
174
+ const acc = timelineMap.get(row.date) ?? { costUsd: 0, estimatedCostUsd: 0, unpricedCount: 0 };
160
175
  acc.costUsd += row.costUsd;
161
176
  acc.estimatedCostUsd += row.estimatedCostUsd;
177
+ acc.unpricedCount += row.unpricedCount ?? 0;
162
178
  timelineMap.set(row.date, acc);
163
179
  }
164
180
  }
@@ -170,7 +186,12 @@ function getDesktopAnalytics(registry, opts) {
170
186
  // Build sorted cost timeline
171
187
  const costTimeline = Array.from(timelineMap.entries())
172
188
  .sort(([a], [b]) => a.localeCompare(b))
173
- .map(([date, v]) => ({ date, costUsd: v.costUsd, estimatedCostUsd: v.estimatedCostUsd }));
189
+ .map(([date, v]) => ({
190
+ date,
191
+ costUsd: v.costUsd,
192
+ estimatedCostUsd: v.estimatedCostUsd,
193
+ ...(v.unpricedCount > 0 ? { unpricedCount: v.unpricedCount } : {}),
194
+ }));
174
195
  // Sort projects by cost descending
175
196
  projectBreakdown.sort((a, b) => b.totalCostUsd - a.totalCostUsd);
176
197
  return {
@@ -179,10 +200,14 @@ function getDesktopAnalytics(registry, opts) {
179
200
  totalCostUsd,
180
201
  estimatedCostUsd,
181
202
  includesEstimated: estimatedCostUsd > 0,
203
+ pricedRuns,
204
+ unpricedRuns,
182
205
  totalJobs,
183
206
  successRate: totalJobs > 0 ? totalSuccess / totalJobs : 0,
184
207
  costToday,
185
208
  estimatedCostToday,
209
+ pricedTodayRuns,
210
+ unpricedTodayRuns,
186
211
  jobsToday,
187
212
  },
188
213
  projectBreakdown,
@@ -221,11 +246,15 @@ function getDesktopTodayStats(registry) {
221
246
  let costToday = 0;
222
247
  let estimatedCostToday = 0;
223
248
  let jobsToday = 0;
249
+ let pricedRuns = 0;
250
+ let unpricedRuns = 0;
224
251
  for (const ctx of registry.listContexts()) {
225
252
  const costRow = ctx.db.prepare(`
226
253
  SELECT
227
254
  COALESCE(SUM(total_cost_usd), 0) as costToday,
228
- COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) as estimatedCostToday
255
+ COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) as estimatedCostToday,
256
+ COUNT(total_cost_usd) as pricedRuns,
257
+ SUM(CASE WHEN total_cost_usd IS NULL THEN 1 ELSE 0 END) as unpricedRuns
229
258
  FROM ai_invocations ${clause}
230
259
  `).get(...params);
231
260
  const jobsRow = ctx.db.prepare(`
@@ -233,9 +262,18 @@ function getDesktopTodayStats(registry) {
233
262
  `).get(...params);
234
263
  costToday += costRow.costToday;
235
264
  estimatedCostToday += costRow.estimatedCostToday;
265
+ pricedRuns += costRow.pricedRuns;
266
+ unpricedRuns += costRow.unpricedRuns ?? 0;
236
267
  jobsToday += jobsRow.jobsToday;
237
268
  }
238
269
  // App-level agent-chat spend (desktop.sqlite), added to the headline figure.
239
270
  costToday += agentCostSince(registry, today);
240
- return { costToday, estimatedCostToday, includesEstimated: estimatedCostToday > 0, jobsToday };
271
+ return {
272
+ costToday,
273
+ estimatedCostToday,
274
+ includesEstimated: estimatedCostToday > 0,
275
+ jobsToday,
276
+ pricedRuns,
277
+ unpricedRuns,
278
+ };
241
279
  }
@@ -107,9 +107,74 @@ function hasCommandFiles(dir) {
107
107
  return false;
108
108
  }
109
109
  }
110
+ function hasProviderSkillFiles(dir) {
111
+ try {
112
+ for (const entry of fs_1.default.readdirSync(dir)) {
113
+ if (fs_1.default.existsSync(path_1.default.join(dir, entry, 'SKILL.md')))
114
+ return true;
115
+ if (entry === 'rails') {
116
+ for (const role of fs_1.default.readdirSync(path_1.default.join(dir, entry))) {
117
+ if (fs_1.default.existsSync(path_1.default.join(dir, entry, role, 'SKILL.md')))
118
+ return true;
119
+ }
120
+ }
121
+ }
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ return false;
127
+ }
110
128
  function hasSpecrails(projectPath) {
111
129
  return hasCommandFiles(path_1.default.join(projectPath, '.claude', 'commands', 'sr'))
112
- || hasCommandFiles(path_1.default.join(projectPath, '.claude', 'commands', 'specrails'));
130
+ || hasCommandFiles(path_1.default.join(projectPath, '.claude', 'commands', 'specrails'))
131
+ || hasProviderSkillFiles(path_1.default.join(projectPath, '.kimi-code', 'skills'));
132
+ }
133
+ function readinessIssue(adapter, detection) {
134
+ if (!detection.installed) {
135
+ return {
136
+ code: 'provider_cli_missing',
137
+ message: `${adapter.displayName} CLI was not found on PATH. Install it, authenticate, then restart Specrails.`,
138
+ };
139
+ }
140
+ if (!detection.executable) {
141
+ return {
142
+ code: 'provider_cli_unusable',
143
+ message: detection.error
144
+ ?? `${adapter.displayName} was found but its executable readiness probe failed. Reinstall it, authenticate, then restart Specrails.`,
145
+ };
146
+ }
147
+ // An adapter with a pinned floor is usable only when the probe positively
148
+ // verifies that floor. Treat an unparseable/unknown version as incompatible;
149
+ // otherwise the UI could advertise a binary that cannot honour our contract.
150
+ if (adapter.minCliVersion && detection.meetsMinimum !== true) {
151
+ return {
152
+ code: 'provider_cli_outdated',
153
+ message: detection.error
154
+ ?? `${adapter.displayName} ${detection.version ?? '(unknown version)'} does not satisfy the required minimum ${adapter.minCliVersion}.`,
155
+ };
156
+ }
157
+ return null;
158
+ }
159
+ async function detectProviderReadiness(adapter) {
160
+ try {
161
+ const detection = await adapter.detectInstalled();
162
+ return { detection, issue: readinessIssue(adapter, detection) };
163
+ }
164
+ catch (err) {
165
+ const detection = {
166
+ installed: false,
167
+ executable: false,
168
+ error: err instanceof Error ? err.message : String(err),
169
+ };
170
+ return {
171
+ detection,
172
+ issue: {
173
+ code: 'provider_cli_unusable',
174
+ message: `${adapter.displayName} readiness probe failed: ${detection.error}`,
175
+ },
176
+ };
177
+ }
113
178
  }
114
179
  function canonicalizePath(resolvedPath) {
115
180
  try {
@@ -293,12 +358,8 @@ function createDesktopRouter(registry, broadcast) {
293
358
  // the multi-provider work. The `SPECRAILS_CODEX_BETA=0` env var is honoured
294
359
  // as an emergency rollback (forces codex back to "unavailable" in the UI
295
360
  // without redeploying) — unset or `1` reports the real detection.
296
- router.get('/available-providers', (_req, res) => {
361
+ router.get('/available-providers', async (_req, res) => {
297
362
  const providers = (0, core_compat_1.detectAvailableCLIs)();
298
- // tiers: quick install is always available (app-driven config); full requires an AI CLI
299
- const tiers = ['quick'];
300
- if (Object.values(providers).some(Boolean))
301
- tiers.push('full');
302
363
  // Return the full detected map (registry-driven) so a newly-registered
303
364
  // provider surfaces here with no edit. Apply per-provider beta gates: codex
304
365
  // is forced unavailable when SPECRAILS_CODEX_BETA=0 (emergency rollback).
@@ -309,7 +370,34 @@ function createDesktopRouter(registry, broadcast) {
309
370
  // SPECRAILS_GEMINI_BETA=0 (emergency rollback, parity with codex).
310
371
  if (isGeminiBetaDisabled())
311
372
  gated.gemini = false;
312
- res.json({ ...gated, tiers });
373
+ const providerIssues = {};
374
+ if (gated.kimi) {
375
+ const readiness = await detectProviderReadiness((0, providers_1.getAdapter)('kimi'));
376
+ if (readiness.issue) {
377
+ gated.kimi = false;
378
+ providerIssues.kimi = readiness.issue;
379
+ }
380
+ else {
381
+ const core = await (0, core_compat_1.checkCoreCompat)();
382
+ if (!(0, core_compat_1.coreCompatSupportsProvider)(core, 'kimi')) {
383
+ gated.kimi = false;
384
+ providerIssues.kimi = {
385
+ code: 'core_provider_unsupported',
386
+ message: 'This Specrails Core build cannot render Kimi skills. Update or reinstall Specrails, then retry.',
387
+ };
388
+ }
389
+ }
390
+ }
391
+ // tiers: quick install is always available (app-driven config); full
392
+ // requires a CLI that also survives provider-specific compatibility gates.
393
+ const tiers = ['quick'];
394
+ if (Object.values(gated).some(Boolean))
395
+ tiers.push('full');
396
+ const launchDescriptors = Object.fromEntries((0, providers_1.listAdapters)().map((adapter) => [
397
+ adapter.id,
398
+ { command: adapter.binary, args: [] },
399
+ ]));
400
+ res.json({ ...gated, tiers, providerIssues, launchDescriptors });
313
401
  });
314
402
  router.get('/setup-prerequisites', (req, res) => {
315
403
  const status = (0, setup_prerequisites_1.getSetupPrerequisitesStatus)();
@@ -335,7 +423,7 @@ function createDesktopRouter(registry, broadcast) {
335
423
  res.json(status);
336
424
  });
337
425
  // POST /api/projects — register a new project by path
338
- router.post('/projects', (req, res) => {
426
+ router.post('/projects', async (req, res) => {
339
427
  const { path: projectPath, name, provider, providers: providersRaw } = req.body ?? {};
340
428
  if (!projectPath || typeof projectPath !== 'string') {
341
429
  res.status(400).json({ error: 'path is required' });
@@ -382,6 +470,27 @@ function createDesktopRouter(registry, broadcast) {
382
470
  });
383
471
  return;
384
472
  }
473
+ if (providers.includes('kimi')) {
474
+ const readiness = await detectProviderReadiness((0, providers_1.getAdapter)('kimi'));
475
+ if (readiness.issue) {
476
+ res.status(409).json({
477
+ code: readiness.issue.code,
478
+ provider: 'kimi',
479
+ error: readiness.issue.message,
480
+ detection: readiness.detection,
481
+ });
482
+ return;
483
+ }
484
+ const core = await (0, core_compat_1.checkCoreCompat)();
485
+ if (!(0, core_compat_1.coreCompatSupportsProvider)(core, 'kimi')) {
486
+ res.status(409).json({
487
+ code: 'core_provider_unsupported',
488
+ provider: 'kimi',
489
+ error: 'This Specrails Core build cannot render Kimi skills. Update or reinstall Specrails, then retry.',
490
+ });
491
+ return;
492
+ }
493
+ }
385
494
  const resolvedPath = path_1.default.resolve(projectPath);
386
495
  // Validate path exists
387
496
  if (!fs_1.default.existsSync(resolvedPath)) {
@@ -537,11 +646,18 @@ function createDesktopRouter(registry, broadcast) {
537
646
  const desktopDailyBudgetUsd = desktopDailyBudgetRaw != null ? parseFloat(desktopDailyBudgetRaw) : null;
538
647
  const costAlertRaw = (0, desktop_db_1.getDesktopSetting)(registry.desktopDb, 'cost_alert_threshold_usd');
539
648
  const costAlertThresholdUsd = costAlertRaw != null ? parseFloat(costAlertRaw) : null;
540
- const { costToday } = (0, desktop_analytics_1.getDesktopTodayStats)(registry);
541
- const budgetUtilizationPct = desktopDailyBudgetUsd != null && desktopDailyBudgetUsd > 0
649
+ const { costToday, pricedRuns, unpricedRuns } = (0, desktop_analytics_1.getDesktopTodayStats)(registry);
650
+ const budgetUtilizationPct = desktopDailyBudgetUsd != null && desktopDailyBudgetUsd > 0 && unpricedRuns === 0
542
651
  ? (costToday / desktopDailyBudgetUsd) * 100
543
652
  : null;
544
- res.json({ desktopDailyBudgetUsd, costAlertThresholdUsd, costToday, budgetUtilizationPct });
653
+ res.json({
654
+ desktopDailyBudgetUsd,
655
+ costAlertThresholdUsd,
656
+ costToday,
657
+ pricedRuns,
658
+ unpricedRuns,
659
+ budgetUtilizationPct,
660
+ });
545
661
  });
546
662
  // PATCH /api/budget — update app-level budget settings
547
663
  router.patch('/budget', (req, res) => {
@@ -17,8 +17,9 @@ const providers_1 = require("./providers");
17
17
  * provider CLI for Explore Spec turns. See openspec/changes/accelerate-spec-
18
18
  * chat-first-token/design.md decisions D1–D3 + D9, and openspec/changes/
19
19
  * add-multi-provider-support/specs/explore-spec/spec.md for the multi-
20
- * provider behaviour (instructions file is adapter-driven: CLAUDE.md for
21
- * claude, AGENTS.md for codex).
20
+ * provider behaviour (the instructions path is adapter-driven: CLAUDE.md for
21
+ * Claude, AGENTS.md for Codex, GEMINI.md for Gemini, and
22
+ * .kimi-code/AGENTS.md for Kimi).
22
23
  *
23
24
  * Layout under `<specrails-home>/.specrails/projects/<slug>/explore-cwd/`:
24
25
  * ├── <adapter.instructionsFilename> — embedded mini-prompt, app-owned
@@ -115,6 +116,9 @@ function ensureExploreCwd(input, baseDir) {
115
116
  fs_1.default.mkdirSync(cwd, { recursive: true });
116
117
  const adapter = (0, providers_1.getAdapter)(input.provider ?? 'claude');
117
118
  const instructionsPath = path_1.default.join(cwd, adapter.instructionsFilename);
119
+ // Provider instruction paths are project-relative, not necessarily
120
+ // top-level filenames (Kimi uses `.kimi-code/AGENTS.md`).
121
+ fs_1.default.mkdirSync(path_1.default.dirname(instructionsPath), { recursive: true });
118
122
  const desiredInstructions = renderExploreInstructions(input.projectName);
119
123
  let currentInstructions = null;
120
124
  try {
@@ -130,7 +134,12 @@ function ensureExploreCwd(input, baseDir) {
130
134
  // — provider is immutable post-creation but the lifecycle code MUST handle
131
135
  // the edge per spec), remove any stale instructions file authored by a
132
136
  // different provider so the explore-cwd doesn't carry both.
133
- const STALE_INSTRUCTION_FILES = ['CLAUDE.md', 'AGENTS.md', 'GEMINI.md'];
137
+ const STALE_INSTRUCTION_FILES = [
138
+ 'CLAUDE.md',
139
+ 'AGENTS.md',
140
+ 'GEMINI.md',
141
+ path_1.default.join('.kimi-code', 'AGENTS.md'),
142
+ ];
134
143
  for (const stale of STALE_INSTRUCTION_FILES) {
135
144
  if (stale === adapter.instructionsFilename)
136
145
  continue;
@@ -140,6 +149,13 @@ function ensureExploreCwd(input, baseDir) {
140
149
  fs_1.default.unlinkSync(stalePath);
141
150
  }
142
151
  catch { /* best-effort */ }
152
+ const staleParent = path_1.default.dirname(stalePath);
153
+ if (staleParent !== cwd) {
154
+ try {
155
+ fs_1.default.rmdirSync(staleParent);
156
+ }
157
+ catch { /* non-empty or already gone */ }
158
+ }
143
159
  }
144
160
  }
145
161
  ensureProjectLink(cwd, input.projectPath);
@@ -30,7 +30,7 @@ function isJiraEnabled() {
30
30
  }
31
31
  /**
32
32
  * Interactive freestyle jobs: when launched with the rail's "Interactive"
33
- * toggle, an freestyle (Claude-only) job becomes a persistent chat session —
33
+ * toggle, a Claude Freestyle job becomes a persistent chat session —
34
34
  * the user sends multiple prompts across turns, the job stays resident until an
35
35
  * explicit "Finalize Job" action, and every turn's real token spend is summed
36
36
  * into the single job row. Server-side default ON; set
@@ -152,9 +152,9 @@ class FileStoryManager {
152
152
  started_at: startedIso,
153
153
  finished_at: new Date((this.deps.now ?? Date.now)()).toISOString(),
154
154
  model: out?.model,
155
- total_cost_usd: out?.costUsd ?? 0,
156
- tokens_in: out?.tokensIn ?? 0,
157
- tokens_out: out?.tokensOut ?? 0,
155
+ total_cost_usd: out?.costUsd ?? undefined,
156
+ tokens_in: out?.tokensIn ?? undefined,
157
+ tokens_out: out?.tokensOut ?? undefined,
158
158
  tokens_cache_read: out?.tokensCacheRead,
159
159
  tokens_cache_create: out?.tokensCacheCreate,
160
160
  duration_ms: out?.durationMs ?? 0,
@@ -9,6 +9,7 @@ const readline_1 = require("readline");
9
9
  const tree_kill_1 = __importDefault(require("tree-kill"));
10
10
  const cli_prompt_1 = require("./util/cli-prompt");
11
11
  const result_event_1 = require("./result-event");
12
+ const runtime_1 = require("./providers/runtime");
12
13
  const GENERATE_TIMEOUT_MS = 60_000;
13
14
  const SYSTEM_PROMPT_EN = 'You are explaining code to a non-developer. Output 2 to 4 sentences in plain language about what the file does. ' +
14
15
  'No code, no jargon, no bullet lists. Output only the explanation, nothing else.';
@@ -54,14 +55,20 @@ function createFileSummaryGenerator(opts) {
54
55
  const startedAt = Date.now();
55
56
  if (signal?.aborted)
56
57
  throw new Error('file-summary generator aborted before start');
57
- const args = adapter.buildArgs('spec-gen', {
58
+ const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter);
59
+ if (!toolPolicy) {
60
+ throw new Error(`provider_tool_policy_unsupported:${adapter.id}:pure-output`);
61
+ }
62
+ const spawnOptions = {
58
63
  prompt: buildUserPrompt(input, adapter, systemPromptFor),
59
64
  systemPrompt: adapter.capabilities.systemPromptArg ? systemPromptFor(input.language) : undefined,
60
65
  model,
61
66
  maxTurns: 1,
62
- });
67
+ toolPolicy,
68
+ };
69
+ const args = adapter.buildArgs('spec-gen', spawnOptions);
63
70
  const child = spawn(adapter.binary, args, {
64
- env: process.env,
71
+ env: (0, runtime_1.buildProviderEnv)(adapter, spawnOptions),
65
72
  stdio: ['ignore', 'pipe', 'pipe'],
66
73
  cwd: opts.cwd,
67
74
  });
@@ -81,10 +88,10 @@ function createFileSummaryGenerator(opts) {
81
88
  return {
82
89
  model: result.model ?? model,
83
90
  provider: adapter.id,
84
- costUsd: result.total_cost_usd ?? 0,
91
+ costUsd: result.total_cost_usd ?? null,
85
92
  costEstimated: estimated,
86
- tokensIn: result.tokens_in ?? 0,
87
- tokensOut: result.tokens_out ?? 0,
93
+ tokensIn: result.tokens_in ?? null,
94
+ tokensOut: result.tokens_out ?? null,
88
95
  tokensCacheRead: result.tokens_cache_read,
89
96
  tokensCacheCreate: result.tokens_cache_create,
90
97
  durationMs: result.duration_ms ?? (Date.now() - startedAt),
@@ -159,12 +166,11 @@ function createFileSummaryGenerator(opts) {
159
166
  }
160
167
  const reader = (0, readline_1.createInterface)({ input: child.stdout, crlfDelay: Infinity });
161
168
  reader.on('line', (line) => {
162
- const ev = adapter.parseStreamLine(line);
163
- if (!ev)
164
- return;
165
- events.push(ev);
166
- if (ev.kind === 'text-delta')
167
- fullText += ev.text;
169
+ for (const ev of (0, runtime_1.parseStreamEvents)(adapter, line)) {
170
+ events.push(ev);
171
+ if (ev.kind === 'text-delta')
172
+ fullText += ev.text;
173
+ }
168
174
  });
169
175
  child.on('error', (err) => {
170
176
  clearTimeout(timer);
@@ -213,10 +219,10 @@ function createFileSummaryGenerator(opts) {
213
219
  summary,
214
220
  model: result.model ?? model,
215
221
  provider: adapter.id,
216
- costUsd: result.total_cost_usd ?? 0,
222
+ costUsd: result.total_cost_usd ?? null,
217
223
  costEstimated: estimated,
218
- tokensIn: result.tokens_in ?? 0,
219
- tokensOut: result.tokens_out ?? 0,
224
+ tokensIn: result.tokens_in ?? null,
225
+ tokensOut: result.tokens_out ?? null,
220
226
  tokensCacheRead: result.tokens_cache_read,
221
227
  tokensCacheCreate: result.tokens_cache_create,
222
228
  durationMs,
@@ -554,9 +554,9 @@ class FileSummaryManager {
554
554
  started_at: startedIso,
555
555
  finished_at: new Date((this.deps.now ?? Date.now)()).toISOString(),
556
556
  model: out.model,
557
- total_cost_usd: out.costUsd,
558
- tokens_in: out.tokensIn,
559
- tokens_out: out.tokensOut,
557
+ total_cost_usd: out.costUsd ?? undefined,
558
+ tokens_in: out.tokensIn ?? undefined,
559
+ tokens_out: out.tokensOut ?? undefined,
560
560
  tokens_cache_read: out.tokensCacheRead,
561
561
  tokens_cache_create: out.tokensCacheCreate,
562
562
  duration_ms: out.durationMs,
@@ -598,9 +598,9 @@ class FileSummaryManager {
598
598
  started_at: startedIso,
599
599
  finished_at: new Date((this.deps.now ?? Date.now)()).toISOString(),
600
600
  model: partial?.model,
601
- total_cost_usd: partial?.costUsd ?? 0,
602
- tokens_in: partial?.tokensIn ?? 0,
603
- tokens_out: partial?.tokensOut ?? 0,
601
+ total_cost_usd: partial?.costUsd ?? undefined,
602
+ tokens_in: partial?.tokensIn ?? undefined,
603
+ tokens_out: partial?.tokensOut ?? undefined,
604
604
  tokens_cache_read: partial?.tokensCacheRead,
605
605
  tokens_cache_create: partial?.tokensCacheCreate,
606
606
  duration_ms: partial?.durationMs ?? 0,