specrails-desktop 2.18.2 → 2.19.1

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 (346) hide show
  1. package/README.md +1 -1
  2. package/client/dist/assets/{ActivityFeedPage-mGnv5SOe.js → ActivityFeedPage-C0_k6n5T.js} +1 -1
  3. package/client/dist/assets/AgentBrowserCapture-NHUCEnTh.js +1 -0
  4. package/client/dist/assets/AgentModeCodePane-jddXrhPY.js +2 -0
  5. package/client/dist/assets/AgentsPage-BPjf6bId.js +86 -0
  6. package/client/dist/assets/AnalyticsPage-BaJjj5mO.js +1 -0
  7. package/client/dist/assets/{BarChart-BqHUOnl9.js → BarChart-HPiao--v.js} +1 -1
  8. package/client/dist/assets/CodePage-CAD4KfkC.js +2 -0
  9. package/client/dist/assets/{DesktopAnalyticsPage-CR-m97Ui.js → DesktopAnalyticsPage-B2RBxIvj.js} +1 -1
  10. package/client/dist/assets/DocsDialog-BJDvUEGj.js +11 -0
  11. package/client/dist/assets/DocsPage-B6H-DBs8.js +11 -0
  12. package/client/dist/assets/{ExportDropdown-C-o1Q4ef.js → ExportDropdown-CYMcbLTD.js} +1 -1
  13. package/client/dist/assets/IntegrationsPage-Dx_UpQVk.js +3 -0
  14. package/client/dist/assets/JobDetailPage-BlTnsRAN.js +16 -0
  15. package/client/dist/assets/JobsPage-EB0PbXOk.js +1 -0
  16. package/client/dist/assets/LoopBuilderPage-DfWfhhJY.js +7 -0
  17. package/client/dist/assets/LoopsPage-DCVATTv5.js +1 -0
  18. package/client/dist/assets/{addspec-B9dY_F5T.js → addspec-BXV6sx5l.js} +1 -1
  19. package/client/dist/assets/{addspec-tbxr3sHa.js → addspec-CS895X6A.js} +1 -1
  20. package/client/dist/assets/{addspec-W0r16BOC2.js → addspec-CXfEOrD42.js} +1 -1
  21. package/client/dist/assets/{addspec-D43TlMVp2.js → addspec-D28kw9ow2.js} +1 -1
  22. package/client/dist/assets/{addspec-B9nhMikb.js → addspec-D39EEg02.js} +1 -1
  23. package/client/dist/assets/{addspec-DfgIZ5lO.js → addspec-DC1tgsFG.js} +1 -1
  24. package/client/dist/assets/{addspec-BtNaJHu2.js → addspec-DcHALPEp.js} +1 -1
  25. package/client/dist/assets/{addspec-BloGn_ey.js → addspec-DxW6oPsk.js} +1 -1
  26. package/client/dist/assets/{agent-Bm2tPrdr.js → agent-B5Ycau5M.js} +1 -1
  27. package/client/dist/assets/{agent-DMUrz9ZS2.js → agent-BEz08l4_2.js} +1 -1
  28. package/client/dist/assets/{agent-C4bO1l_v.js → agent-BIX51CEA.js} +1 -1
  29. package/client/dist/assets/{agent-9WdSxPU5.js → agent-Bc9Kwf65.js} +1 -1
  30. package/client/dist/assets/{agent-pO8x4jbR.js → agent-BiM7puyn.js} +1 -1
  31. package/client/dist/assets/{agent-CgKsh88Z2.js → agent-C0kYSv3m2.js} +1 -1
  32. package/client/dist/assets/agent-CCzWlfqs.js +1 -0
  33. package/client/dist/assets/{agent-ASIyVcg0.js → agent-DiCSo31C.js} +1 -1
  34. package/client/dist/assets/{agents-DfGvYtpq2.js → agents-BFrHy5d-2.js} +1 -1
  35. package/client/dist/assets/{agents-Dli56gr82.js → agents-BFy2Kq_k2.js} +1 -1
  36. package/client/dist/assets/{agents-C07al8rI.js → agents-BXDCFJQa.js} +1 -1
  37. package/client/dist/assets/{agents-BAxAwHy-.js → agents-BySH0Gvw.js} +1 -1
  38. package/client/dist/assets/{agents-Eqw_AQ6H.js → agents-CTdwacTO.js} +1 -1
  39. package/client/dist/assets/{agents-BjT_xLjv.js → agents-Cev2oFfX.js} +1 -1
  40. package/client/dist/assets/{agents-BUYBb825.js → agents-CsDEv4Fj.js} +1 -1
  41. package/client/dist/assets/{agents-52t8NVpS.js → agents-z0kA-y0Q.js} +1 -1
  42. package/client/dist/assets/dashboard-Bl2_Yjs6.js +1 -0
  43. package/client/dist/assets/dashboard-C_vS9RaM2.js +1 -0
  44. package/client/dist/assets/dashboard-CcEpALV_.js +1 -0
  45. package/client/dist/assets/dashboard-CfltY66K.js +1 -0
  46. package/client/dist/assets/dashboard-CoED_41r.js +1 -0
  47. package/client/dist/assets/dashboard-DLeC5ziO.js +1 -0
  48. package/client/dist/assets/dashboard-DxEPkALo2.js +1 -0
  49. package/client/dist/assets/dashboard-MgDVmaYS2.js +1 -0
  50. package/client/dist/assets/{dist-js-CUegfF6k.js → dist-js-ClEfL6Bo.js} +1 -1
  51. package/client/dist/assets/{dist-js-BHhtSerX.js → dist-js-b2_z7zAi.js} +1 -1
  52. package/client/dist/assets/index-9yNUBwEi.css +2 -0
  53. package/client/dist/assets/{index-B7vB20Jw.js → index-BeujshsU.js} +57 -57
  54. package/client/dist/assets/{lib-PQoHlR5u.js → lib-CfphudAm.js} +1 -1
  55. package/client/dist/assets/loops-BEUiCzEI.js +1 -0
  56. package/client/dist/assets/loops-BlrQiK122.js +1 -0
  57. package/client/dist/assets/loops-Bs0ectZ32.js +1 -0
  58. package/client/dist/assets/loops-CLZV8HHY2.js +1 -0
  59. package/client/dist/assets/loops-CQuuMlyZ.js +1 -0
  60. package/client/dist/assets/loops-DuuWQWTI.js +1 -0
  61. package/client/dist/assets/loops-KOTryzk5.js +1 -0
  62. package/client/dist/assets/loops-t1mUZtf0.js +1 -0
  63. package/client/dist/assets/nav--1ErXZrS.js +1 -0
  64. package/client/dist/assets/nav-18nqSJ8h.js +1 -0
  65. package/client/dist/assets/nav-BuonHb17.js +1 -0
  66. package/client/dist/assets/nav-C-sCoOLY2.js +1 -0
  67. package/client/dist/assets/nav-ClXz_3Ic2.js +1 -0
  68. package/client/dist/assets/nav-CtqgSQeE2.js +1 -0
  69. package/client/dist/assets/nav-S3YvCaVv.js +1 -0
  70. package/client/dist/assets/nav-czg8NkN-.js +1 -0
  71. package/client/dist/assets/settings-BOZBX-Vq.js +1 -0
  72. package/client/dist/assets/settings-CX29QcQW.js +1 -0
  73. package/client/dist/assets/settings-CfOWHPzc2.js +1 -0
  74. package/client/dist/assets/settings-DaXhxNug2.js +1 -0
  75. package/client/dist/assets/settings-DmyDpuzu.js +1 -0
  76. package/client/dist/assets/settings-DwPRLcxr2.js +1 -0
  77. package/client/dist/assets/settings-MjYVJvDE.js +1 -0
  78. package/client/dist/assets/settings-zJFdTzKE.js +1 -0
  79. package/client/dist/assets/{setup-BYoDYoPY2.js → setup-BmXfxlzA2.js} +1 -1
  80. package/client/dist/assets/{setup-faMApo0U2.js → setup-BxVydxbl2.js} +1 -1
  81. package/client/dist/assets/{setup-C5UbM0RP.js → setup-DIRZ1Lf-.js} +1 -1
  82. package/client/dist/assets/{setup-Bf9eLKxU.js → setup-DwbKSnKQ.js} +1 -1
  83. package/client/dist/assets/{setup-JFkWWZnR.js → setup-Dx13pESZ.js} +1 -1
  84. package/client/dist/assets/{setup-CqGrWb6G.js → setup-G4ZvDKxX.js} +1 -1
  85. package/client/dist/assets/{setup-tloaTobG2.js → setup-SLAi4xxQ2.js} +1 -1
  86. package/client/dist/assets/{setup-4us-Bz3H.js → setup-Z01j3st4.js} +1 -1
  87. package/client/dist/assets/{upload-PnJDPHZH.js → upload-Ox9jUq1X.js} +1 -1
  88. package/client/dist/assets/{value-BTDefcOV.js → value-BeQVX5gN.js} +1 -1
  89. package/client/dist/index.html +10 -10
  90. package/docs/codex.md +5 -5
  91. package/docs/customizing.md +4 -4
  92. package/docs/gemini.md +2 -2
  93. package/docs/getting-started.md +1 -1
  94. package/docs/guide/de/integrations/1-ai-providers.md +2 -2
  95. package/docs/guide/de/integrations/5-mcp-server.md +20 -1
  96. package/docs/guide/de/pipeline/1-rails-and-jobs.md +4 -4
  97. package/docs/guide/de/pipeline/2-the-job-detail-view.md +1 -1
  98. package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +2 -2
  99. package/docs/guide/de/pipeline/5-the-loop-builder.md +2 -2
  100. package/docs/guide/en/integrations/1-ai-providers.md +2 -2
  101. package/docs/guide/en/integrations/5-mcp-server.md +20 -1
  102. package/docs/guide/en/pipeline/1-rails-and-jobs.md +4 -4
  103. package/docs/guide/en/pipeline/2-the-job-detail-view.md +1 -1
  104. package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +2 -2
  105. package/docs/guide/en/pipeline/5-the-loop-builder.md +2 -2
  106. package/docs/guide/es/integrations/1-ai-providers.md +2 -2
  107. package/docs/guide/es/integrations/5-mcp-server.md +20 -1
  108. package/docs/guide/es/pipeline/1-rails-and-jobs.md +4 -4
  109. package/docs/guide/es/pipeline/2-the-job-detail-view.md +1 -1
  110. package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +2 -2
  111. package/docs/guide/es/pipeline/5-the-loop-builder.md +2 -2
  112. package/docs/guide/fr/integrations/1-ai-providers.md +2 -2
  113. package/docs/guide/fr/integrations/5-mcp-server.md +20 -1
  114. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +4 -4
  115. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +1 -1
  116. package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +2 -2
  117. package/docs/guide/fr/pipeline/5-the-loop-builder.md +2 -2
  118. package/docs/guide/it/integrations/1-ai-providers.md +2 -2
  119. package/docs/guide/it/integrations/5-mcp-server.md +20 -1
  120. package/docs/guide/it/pipeline/1-rails-and-jobs.md +4 -4
  121. package/docs/guide/it/pipeline/2-the-job-detail-view.md +1 -1
  122. package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +2 -2
  123. package/docs/guide/it/pipeline/5-the-loop-builder.md +2 -2
  124. package/docs/guide/ja/integrations/1-ai-providers.md +2 -2
  125. package/docs/guide/ja/integrations/5-mcp-server.md +20 -1
  126. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +4 -4
  127. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +1 -1
  128. package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +2 -2
  129. package/docs/guide/ja/pipeline/5-the-loop-builder.md +2 -2
  130. package/docs/guide/pt/integrations/1-ai-providers.md +2 -2
  131. package/docs/guide/pt/integrations/5-mcp-server.md +20 -1
  132. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +4 -4
  133. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +1 -1
  134. package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +2 -2
  135. package/docs/guide/pt/pipeline/5-the-loop-builder.md +2 -2
  136. package/docs/guide/zh/integrations/1-ai-providers.md +2 -2
  137. package/docs/guide/zh/integrations/5-mcp-server.md +20 -1
  138. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +4 -4
  139. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +1 -1
  140. package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +2 -2
  141. package/docs/guide/zh/pipeline/5-the-loop-builder.md +2 -2
  142. package/docs/internals/switch-to-agent-mode-design.md +301 -0
  143. package/docs/internals/visual-design-audit.md +184 -0
  144. package/docs/mcp.md +26 -1
  145. package/docs/running-pipelines.md +10 -10
  146. package/docs/tracking-cost.md +1 -1
  147. package/package.json +1 -1
  148. package/server/dist/agent-chat-manager.js +107 -33
  149. package/server/dist/agent-chat-router.js +170 -8
  150. package/server/dist/agent-cwd-manager.js +2 -47
  151. package/server/dist/agent-operator-prompt.js +277 -0
  152. package/server/dist/agent-store.js +27 -5
  153. package/server/dist/attachment-manager.js +138 -0
  154. package/server/dist/desktop-db.js +15 -0
  155. package/server/dist/loop-factory.js +12 -2
  156. package/server/dist/mcp/guide.js +186 -51
  157. package/server/dist/mcp/tools/analytics.js +1 -1
  158. package/server/dist/mcp/tools/app-settings.js +45 -5
  159. package/server/dist/mcp/tools/chat.js +9 -2
  160. package/server/dist/mcp/tools/code.js +3 -2
  161. package/server/dist/mcp/tools/jobs.js +18 -6
  162. package/server/dist/mcp/tools/loops.js +57 -5
  163. package/server/dist/mcp/tools/meta.js +43 -3
  164. package/server/dist/mcp/tools/rails.js +6 -6
  165. package/server/dist/mcp/tools/setup.js +2 -1
  166. package/server/dist/mcp/tools/specs.js +60 -38
  167. package/server/dist/mcp/tools/types.js +17 -8
  168. package/server/dist/mcp/tools/watch.js +71 -8
  169. package/server/dist/project-router-helpers.js +1 -1
  170. package/server/dist/project-router-tickets.js +43 -4
  171. package/server/dist/providers/claude-adapter.js +6 -0
  172. package/server/dist/providers/codex-adapter.js +10 -0
  173. package/server/dist/providers/gemini-adapter.js +3 -0
  174. package/server/dist/rails-router.js +8 -17
  175. package/server/dist/spec-models.js +1 -0
  176. package/client/dist/assets/AgentsPage-BH1isg5j.js +0 -86
  177. package/client/dist/assets/AnalyticsPage-ByyshYRI.js +0 -1
  178. package/client/dist/assets/CodePage-CU7T_HYs.js +0 -2
  179. package/client/dist/assets/DocsDialog-CEmZp_8V.js +0 -11
  180. package/client/dist/assets/DocsPage-DYbAQ1AT.js +0 -11
  181. package/client/dist/assets/IntegrationsPage-C6fKdwVH.js +0 -3
  182. package/client/dist/assets/JobDetailPage-CKfIfBgE.js +0 -16
  183. package/client/dist/assets/JobsPage-nBng0riZ.js +0 -1
  184. package/client/dist/assets/LoopBuilderPage-Co_TYqYk.js +0 -7
  185. package/client/dist/assets/LoopsPage-a2hd37Ya.js +0 -1
  186. package/client/dist/assets/agent-Dwkz5mPS.js +0 -1
  187. package/client/dist/assets/dashboard-BTiH361F.js +0 -1
  188. package/client/dist/assets/dashboard-COSm_14E.js +0 -1
  189. package/client/dist/assets/dashboard-CfOs70FN2.js +0 -1
  190. package/client/dist/assets/dashboard-Cyzp4ox9.js +0 -1
  191. package/client/dist/assets/dashboard-CzHDp14_2.js +0 -1
  192. package/client/dist/assets/dashboard-D6Woy2B5.js +0 -1
  193. package/client/dist/assets/dashboard-DwbH4oVH.js +0 -1
  194. package/client/dist/assets/dashboard-cWhU3krA2.js +0 -1
  195. package/client/dist/assets/index-B0FxQALR.css +0 -2
  196. package/client/dist/assets/loops-BDhEfnx82.js +0 -1
  197. package/client/dist/assets/loops-BM5QggwH.js +0 -1
  198. package/client/dist/assets/loops-CPjLAAxj.js +0 -1
  199. package/client/dist/assets/loops-D8Iu6Jss.js +0 -1
  200. package/client/dist/assets/loops-DKnk79TB2.js +0 -1
  201. package/client/dist/assets/loops-DLW0aFMm.js +0 -1
  202. package/client/dist/assets/loops-Dcv3dFy_2.js +0 -1
  203. package/client/dist/assets/loops-y7wFRx6M.js +0 -1
  204. package/client/dist/assets/nav-1hj2izqB2.js +0 -1
  205. package/client/dist/assets/nav-BBUKMAu-2.js +0 -1
  206. package/client/dist/assets/nav-CLqkP-26.js +0 -1
  207. package/client/dist/assets/nav-Cv46L837.js +0 -1
  208. package/client/dist/assets/nav-DE3yWQw6.js +0 -1
  209. package/client/dist/assets/nav-DgA-rjLk2.js +0 -1
  210. package/client/dist/assets/nav-EG2pr6vN.js +0 -1
  211. package/client/dist/assets/nav-r3mIJVfU.js +0 -1
  212. package/client/dist/assets/settings-BKmORxlB2.js +0 -1
  213. package/client/dist/assets/settings-BVv2JgQ8.js +0 -1
  214. package/client/dist/assets/settings-Bghm3pAV.js +0 -1
  215. package/client/dist/assets/settings-BuC_aplX.js +0 -1
  216. package/client/dist/assets/settings-Bw_Qk8E32.js +0 -1
  217. package/client/dist/assets/settings-CAKgJv7p.js +0 -1
  218. package/client/dist/assets/settings-CEUgk1Ck.js +0 -1
  219. package/client/dist/assets/settings-C_PDE20s2.js +0 -1
  220. /package/client/dist/assets/{activity-Uj576ckT.js → activity-BlvN5rhP.js} +0 -0
  221. /package/client/dist/assets/{activity-w1qMFwxh.js → activity-C5SeKbom.js} +0 -0
  222. /package/client/dist/assets/{activity-BySXFT2J2.js → activity-DIJexk6v2.js} +0 -0
  223. /package/client/dist/assets/{activity-B82z3Pna.js → activity-DLdwUYv7.js} +0 -0
  224. /package/client/dist/assets/{activity-BVpZrs0J.js → activity-DOKV_Wyf.js} +0 -0
  225. /package/client/dist/assets/{activity-BId0pwuS2.js → activity-DVuiy8TI2.js} +0 -0
  226. /package/client/dist/assets/{activity-DIWnV0Pl.js → activity-Dsf3J7iW.js} +0 -0
  227. /package/client/dist/assets/{agentstudio-C7xxqVWn.js → agentstudio-B8H2H4Db2.js} +0 -0
  228. /package/client/dist/assets/{agentstudio-D-UoNAIA.js → agentstudio-B9zthaTJ.js} +0 -0
  229. /package/client/dist/assets/{agentstudio-0o3XKrcy.js → agentstudio-BDMpU01s.js} +0 -0
  230. /package/client/dist/assets/{agentstudio-Bu8m5jDw.js → agentstudio-CSZo7p8K.js} +0 -0
  231. /package/client/dist/assets/{agentstudio-ObTpVbBP.js → agentstudio-CdD6J23W.js} +0 -0
  232. /package/client/dist/assets/{agentstudio-PzFB3vfh2.js → agentstudio-D80fZu_M2.js} +0 -0
  233. /package/client/dist/assets/{agentstudio-OJjjz6Uf2.js → agentstudio-EuKglkaF2.js} +0 -0
  234. /package/client/dist/assets/{aiedit-DRrNiaB4.js → aiedit-B_VOTUo42.js} +0 -0
  235. /package/client/dist/assets/{aiedit-sP_iao2j.js → aiedit-Cxoe_0wv.js} +0 -0
  236. /package/client/dist/assets/{aiedit-DAM_WRAl2.js → aiedit-D59sPapq2.js} +0 -0
  237. /package/client/dist/assets/{aiedit-BaLZalLa.js → aiedit-DX3BBpXF.js} +0 -0
  238. /package/client/dist/assets/{aiedit-BIQqv2XM2.js → aiedit-GYOYWCHJ2.js} +0 -0
  239. /package/client/dist/assets/{aiedit-BjlUzasF.js → aiedit-TON-4N9S.js} +0 -0
  240. /package/client/dist/assets/{aiedit-BmDufyGU.js → aiedit-ybQmdsST.js} +0 -0
  241. /package/client/dist/assets/{analytics-MVJRjcY52.js → analytics-B2jjXLCP2.js} +0 -0
  242. /package/client/dist/assets/{analytics-C4z_NgJZ.js → analytics-BTkXLTfa.js} +0 -0
  243. /package/client/dist/assets/{analytics-DL2vJCbq.js → analytics-BotqRU_R.js} +0 -0
  244. /package/client/dist/assets/{analytics-e1mkNTgy2.js → analytics-Ck3vl2Qo2.js} +0 -0
  245. /package/client/dist/assets/{analytics-Ds_PNxtO2.js → analytics-CqMJQb7N.js} +0 -0
  246. /package/client/dist/assets/{analytics-B_rxNC9X.js → analytics-DGOoMkaZ.js} +0 -0
  247. /package/client/dist/assets/{analytics-BDqqCzN9.js → analytics-DL7uwNAI2.js} +0 -0
  248. /package/client/dist/assets/{attachments-BP0Ac1yt.js → attachments-7w-BR2V2.js} +0 -0
  249. /package/client/dist/assets/{attachments-CPBVeHX72.js → attachments-B5QX1Xfa2.js} +0 -0
  250. /package/client/dist/assets/{attachments-Db7JfA8a.js → attachments-BcE7kZG-2.js} +0 -0
  251. /package/client/dist/assets/{attachments-CJaO1vCH.js → attachments-BsJJXFzT.js} +0 -0
  252. /package/client/dist/assets/{attachments-8QCKHCEF2.js → attachments-Cbh4AwjP.js} +0 -0
  253. /package/client/dist/assets/{attachments-CV2uaTGE.js → attachments-D0fGlFve.js} +0 -0
  254. /package/client/dist/assets/{attachments-CaOjdN332.js → attachments-D3DJpd3e2.js} +0 -0
  255. /package/client/dist/assets/{browser-C9rUUxo4.js → browser-9GR11iTi.js} +0 -0
  256. /package/client/dist/assets/{browser-CEqx11iy.js → browser-BOxg0p3n.js} +0 -0
  257. /package/client/dist/assets/{browser-543jbxE4.js → browser-BSh8xUWV.js} +0 -0
  258. /package/client/dist/assets/{browser-CLC0etB_2.js → browser-CaV3BJNY2.js} +0 -0
  259. /package/client/dist/assets/{browser-0xeW8fUa2.js → browser-CmWGMRGf2.js} +0 -0
  260. /package/client/dist/assets/{browser-ExmELH702.js → browser-D6wbpBOL2.js} +0 -0
  261. /package/client/dist/assets/{browser-DyG2l9Wa.js → browser-dsgDU1HB.js} +0 -0
  262. /package/client/dist/assets/{chat-DagUyoVA.js → chat-B90iLDI4.js} +0 -0
  263. /package/client/dist/assets/{chat-Cu6F3d6g2.js → chat-CAo0jCnj2.js} +0 -0
  264. /package/client/dist/assets/{chat-CN8BMAMc.js → chat-CW54IP3u.js} +0 -0
  265. /package/client/dist/assets/{chat-NQPCBQo72.js → chat-CYHUUW0p2.js} +0 -0
  266. /package/client/dist/assets/{chat-CCytD3P8.js → chat-D1PXX_p2.js} +0 -0
  267. /package/client/dist/assets/{chat-IjutwlBg.js → chat-DhpcWjOf.js} +0 -0
  268. /package/client/dist/assets/{chat-vVpwkOp52.js → chat-cFG-UfRA2.js} +0 -0
  269. /package/client/dist/assets/{code-Dhb6jbAU.js → code--qUk_yn-.js} +0 -0
  270. /package/client/dist/assets/{code-Ce-nBIwj.js → code-B1aOMCVV.js} +0 -0
  271. /package/client/dist/assets/{code-BaG05zK62.js → code-B5UrmjaE2.js} +0 -0
  272. /package/client/dist/assets/{code-Dap54vOb.js → code-CjBHU0nw.js} +0 -0
  273. /package/client/dist/assets/{code-_NOCo-Ol2.js → code-Cjv4_HkK2.js} +0 -0
  274. /package/client/dist/assets/{code-32l6Naxu2.js → code-D7GLAjrz2.js} +0 -0
  275. /package/client/dist/assets/{code-C5cibF2F.js → code-DZKjfzBN.js} +0 -0
  276. /package/client/dist/assets/{commands-Cc2WpuXa.js → commands-B9XaopQC.js} +0 -0
  277. /package/client/dist/assets/{commands-k9wbNYoi.js → commands-BCx1uDIE.js} +0 -0
  278. /package/client/dist/assets/{commands-CM99Upsz2.js → commands-Bhw9Hqsa2.js} +0 -0
  279. /package/client/dist/assets/{commands-Bc8y9eNo2.js → commands-D0RnooQF2.js} +0 -0
  280. /package/client/dist/assets/{commands-Bl3-KVfj.js → commands-DuaQT-it.js} +0 -0
  281. /package/client/dist/assets/{commands-DASXJD-l.js → commands-MqNuGGO4.js} +0 -0
  282. /package/client/dist/assets/{commands-C5WQ9blx2.js → commands-oB9q2vy_2.js} +0 -0
  283. /package/client/dist/assets/{common-CHARW6MZ2.js → common-BXzqeuiC2.js} +0 -0
  284. /package/client/dist/assets/{common-0aY9HQBP.js → common-BaJ6MF7T.js} +0 -0
  285. /package/client/dist/assets/{common-CQCJzAQq2.js → common-C-jaOdxz2.js} +0 -0
  286. /package/client/dist/assets/{common-DNhhqjlJ.js → common-CKjy-R8-.js} +0 -0
  287. /package/client/dist/assets/{common-YdyZtmaI2.js → common-CRd-Ge5u2.js} +0 -0
  288. /package/client/dist/assets/{common-5jScBJqt.js → common-DPGR3Tfo.js} +0 -0
  289. /package/client/dist/assets/{common-BdaRciTu.js → common-wEB9RBdf.js} +0 -0
  290. /package/client/dist/assets/{explore-ChtxIiSM.js → explore-B_79NLR5.js} +0 -0
  291. /package/client/dist/assets/{explore-BzdMEpuf.js → explore-D-htKul_.js} +0 -0
  292. /package/client/dist/assets/{explore-B82VMUJ_.js → explore-D5b2jgvR.js} +0 -0
  293. /package/client/dist/assets/{explore-DfcUfiPw2.js → explore-Dvp-5qOw2.js} +0 -0
  294. /package/client/dist/assets/{explore-CbW0381i2.js → explore-FaKfWCr72.js} +0 -0
  295. /package/client/dist/assets/{explore-BGz1rvQE.js → explore-IS8VyaSZ.js} +0 -0
  296. /package/client/dist/assets/{explore-yRF7wFSp2.js → explore-OZhWV0Eb2.js} +0 -0
  297. /package/client/dist/assets/{format-command-D96da4fZ.js → format-command-CHImQv6W.js} +0 -0
  298. /package/client/dist/assets/{integrations-CnrX7vqw2.js → integrations-B97cGWfo2.js} +0 -0
  299. /package/client/dist/assets/{integrations-BJvrlcc7.js → integrations-Bp3leAh3.js} +0 -0
  300. /package/client/dist/assets/{integrations-CPKYkG36.js → integrations-C3Ma3GdM.js} +0 -0
  301. /package/client/dist/assets/{integrations-BA5pM05t.js → integrations-C5MUA-0-.js} +0 -0
  302. /package/client/dist/assets/{integrations-B0OBPU9_.js → integrations-CiQbCn_W.js} +0 -0
  303. /package/client/dist/assets/{integrations-DeJFRyXz2.js → integrations-Du_0rDfi2.js} +0 -0
  304. /package/client/dist/assets/{integrations-DBou159M2.js → integrations-t4X5UVcx2.js} +0 -0
  305. /package/client/dist/assets/{jira-mi37H4Kt.js → jira-B1XaR6fj.js} +0 -0
  306. /package/client/dist/assets/{jira-Srx2P5zS.js → jira-BCHx9zUF.js} +0 -0
  307. /package/client/dist/assets/{jira-DeotPx6P2.js → jira-BqXyykbt2.js} +0 -0
  308. /package/client/dist/assets/{jira-BwLBgmfI2.js → jira-BzFvFn7t2.js} +0 -0
  309. /package/client/dist/assets/{jira-BDgxAFTF2.js → jira-D6IDTIsc2.js} +0 -0
  310. /package/client/dist/assets/{jira-NwlUCcQD.js → jira-DSZ5xFRl.js} +0 -0
  311. /package/client/dist/assets/{jira-D3GGzXOI.js → jira-DdEKW9Pu.js} +0 -0
  312. /package/client/dist/assets/{jobs-D8adm2BX.js → jobs-BX9dP3Qn.js} +0 -0
  313. /package/client/dist/assets/{jobs-B56vQEkh2.js → jobs-BgHEgCWk2.js} +0 -0
  314. /package/client/dist/assets/{jobs-K_Y8KAZ2.js → jobs-CU-khJTt.js} +0 -0
  315. /package/client/dist/assets/{jobs-BYIk6Tg_.js → jobs-Ce0SE81t.js} +0 -0
  316. /package/client/dist/assets/{jobs-C-lM-iax2.js → jobs-CeOcGHd_2.js} +0 -0
  317. /package/client/dist/assets/{jobs-CYdevGgT.js → jobs-Ct5v2p6T.js} +0 -0
  318. /package/client/dist/assets/{jobs-OwM0ZWhI2.js → jobs-m7L0K9uC2.js} +0 -0
  319. /package/client/dist/assets/{mcp-D3E4_Mmk2.js → mcp-4QbfLPa4.js} +0 -0
  320. /package/client/dist/assets/{mcp-B6nwJJmR.js → mcp-CXy61khH.js} +0 -0
  321. /package/client/dist/assets/{mcp-CNgFiTEh.js → mcp-CmOBPDjE.js} +0 -0
  322. /package/client/dist/assets/{mcp-mupPuPDO2.js → mcp-NlLc9T8u2.js} +0 -0
  323. /package/client/dist/assets/{mcp-B4irfLJ2.js → mcp-_DUUXTHB2.js} +0 -0
  324. /package/client/dist/assets/{mcp-BP7PpbDr2.js → mcp-dlOyUQQy2.js} +0 -0
  325. /package/client/dist/assets/{mcp-BOoEGTSQ.js → mcp-zqSVP7nA.js} +0 -0
  326. /package/client/dist/assets/{specs-D4z5d8uq.js → specs-57pue7UQ.js} +0 -0
  327. /package/client/dist/assets/{specs-CWNKAScX2.js → specs-BWQ-0EXt2.js} +0 -0
  328. /package/client/dist/assets/{specs-B8mwScoM2.js → specs-BYSOlQRw2.js} +0 -0
  329. /package/client/dist/assets/{specs-B5XOoH-02.js → specs-CkP0B28v2.js} +0 -0
  330. /package/client/dist/assets/{specs-DgvIRZtM.js → specs-RSYuLgF4.js} +0 -0
  331. /package/client/dist/assets/{specs-DuRzE5wE.js → specs-d-zU7_3Q.js} +0 -0
  332. /package/client/dist/assets/{specs-Bj_3fDrQ.js → specs-nM5Cpcqe.js} +0 -0
  333. /package/client/dist/assets/{terminal-DoMTHedv2.js → terminal-Adi3W-GZ2.js} +0 -0
  334. /package/client/dist/assets/{terminal-DOwfkxqa2.js → terminal-BA6FCZna2.js} +0 -0
  335. /package/client/dist/assets/{terminal-CH0fdHvP.js → terminal-BCIUSkrg.js} +0 -0
  336. /package/client/dist/assets/{terminal-B2sExUis.js → terminal-C8KlD61D.js} +0 -0
  337. /package/client/dist/assets/{terminal-DjSSa5qP.js → terminal-D3RTuBwy.js} +0 -0
  338. /package/client/dist/assets/{terminal-w0i-OCp32.js → terminal-DCkOEjSj2.js} +0 -0
  339. /package/client/dist/assets/{terminal-CPMigUX7.js → terminal-DOuNm2BI.js} +0 -0
  340. /package/client/dist/assets/{tickets-D00mSt832.js → tickets-B2q36GlQ2.js} +0 -0
  341. /package/client/dist/assets/{tickets-CQTana1u.js → tickets-Bsyv_znj.js} +0 -0
  342. /package/client/dist/assets/{tickets-D7CSuWjO.js → tickets-C_UPra_1.js} +0 -0
  343. /package/client/dist/assets/{tickets-heDAaj8C2.js → tickets-D72LbUtU2.js} +0 -0
  344. /package/client/dist/assets/{tickets-DvbFg_-c2.js → tickets-DDjU7UfE2.js} +0 -0
  345. /package/client/dist/assets/{tickets-onKZz6Dd.js → tickets-DR4ZrPMf.js} +0 -0
  346. /package/client/dist/assets/{tickets-Dq7HDy8n.js → tickets-DiUA3rXq.js} +0 -0
@@ -10,73 +10,208 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.SPECRAILS_GUIDE = void 0;
11
11
  exports.SPECRAILS_GUIDE = `# Specrails Desktop — Agent Guide
12
12
 
13
- You are operating Specrails Desktop through its MCP server. Specrails is a local
14
- dashboard + pipeline runner that manages multiple software projects and drives AI
15
- coding agents (Claude Code, Codex, Gemini) to implement specs.
13
+ You are operating Specrails Desktop through its MCP server — either as an
14
+ EXTERNAL MCP client (Claude Desktop, Cursor, a custom agent) or as the app's own
15
+ embedded agent chat. Everything here applies to both, except Permissions, which
16
+ differs by client kind (see below).
16
17
 
17
- ## Core concepts
18
+ Specrails is a local dashboard + pipeline runner that manages multiple software
19
+ projects (registered repositories) and drives AI coding agents (Claude Code,
20
+ Codex, Gemini) to implement specs.
21
+
22
+ ## The object model
18
23
 
19
24
  - **Project**: a registered repository. Almost every tool is project-scoped and
20
- takes a \`projectId\`. Use \`specrails_select_project\` to set an active project so
21
- you can omit \`projectId\` on later calls; pass an explicit \`projectId\` to override.
22
- - **Spec / ticket**: a unit of work in a project's backlog. Statuses: \`draft\`,
23
- \`todo\`, \`in_progress\`, \`done\`, \`cancelled\`. Priorities: \`critical\`, \`high\`,
24
- \`medium\`, \`low\`. INVARIANT: priority may be null ONLY when status is \`draft\`.
25
- - **Rail**: a launch slot that runs the AI pipeline over one or more assigned
26
- tickets. Modes: \`implement\`, \`batch-implement\`, \`ultracode\`, \`loop\`. Launching a
27
- rail spawns AI CLI processes that write code, run tests and commit — it costs
28
- money and runs for minutes.
29
- - **Job**: one spawned pipeline run. Jobs stream logs/events over the WebSocket
30
- and settle (completed/failed/canceled). Cost is authoritative for Claude and
31
- estimated for Codex/Gemini.
32
- - **Profile**: a per-project agent configuration (which agents, which models,
33
- routing). Profiles are CLAUDE-ONLY; they are ignored for Codex/Gemini rails.
34
- - **Provider / engine**: claude, codex, or gemini. A project installs one or
35
- more. A requested provider must be one of the project's installed providers.
36
- - **Loop**: a saved, app-driven workflow graph runnable on a rail in \`loop\` mode.
25
+ takes a \`projectId\`. \`specrails_select_project\` sets a sticky active project
26
+ so later calls can omit it; an explicit \`projectId\` overrides.
27
+ \`specrails_projects(get)\` includes the repo's absolute path.
28
+ - **Spec / ticket**: a unit of work in a project's backlog. Statuses \`draft\`,
29
+ \`todo\`, \`in_progress\`, \`done\`, \`cancelled\`, plus a \`needs_review\` boolean FLAG
30
+ set on \`done\` specs when the pipeline ships with partial confidence (it is
31
+ not a status). Priorities \`critical|high|medium|low\`. INVARIANT: priority may
32
+ be null ONLY when status is \`draft\`. Specs can be epics with children (see
33
+ SMASH) and can be Jira-backed (\`source: 'jira'\`).
34
+ - **Rail**: a persistent numbered launch slot that runs the AI pipeline over its
35
+ assigned tickets. A rail REMEMBERS its config across launches: ticket ids,
36
+ mode, profile, engine, name. Launching spawns AI CLI processes that write
37
+ code, run tests and commit — it costs money and runs for minutes.
38
+ - **Job**: one spawned pipeline run. Jobs stream events over the app's bus and
39
+ settle (completed/failed/canceled). Job outcome mutates spec status
40
+ AUTOMATICALLY: launch → \`in_progress\`; success → \`done\`; revert → \`todo\`;
41
+ partial confidence → \`done\` + \`needs_review\`. Do not patch statuses the
42
+ pipeline manages.
43
+ - **Loop**: an APP-LEVEL saved workflow graph (not project-scoped). Author with
44
+ \`specrails_loops\`; RUN it with \`specrails_rails(launch, mode:'loop', loopId)\`.
45
+ - **Profile**: per-project agent configuration (which agents, which models,
46
+ routing). CLAUDE-ONLY; forced to null for codex/gemini rails.
47
+ - **Provider / engine**: claude, codex or gemini. A project installs one or
48
+ more; a requested engine must be one of the installed set.
37
49
  - **Plugin**: an MCP-based integration installed per project (e.g. serena).
38
50
 
51
+ ## Creating specs — three paths, one decision rule
52
+
53
+ 1. **Quick (AI-generated)** — \`specrails_specs(action:'generate', idea, …)\`, or
54
+ the simpler \`create\` with title/description: routes through the app's Quick
55
+ Add Spec — an AI pass structures the request into a complete spec, so
56
+ MCP-created specs are indistinguishable from UI-created ones. \`generate\`
57
+ additionally accepts \`contextScope\`, \`attachmentIds\`, \`createLocal\`. Async
58
+ (202): watch the returned ref. Use for clear, well-scoped requests.
59
+ 2. **Explore (multi-turn refinement)** — when requirements are fuzzy:
60
+ - \`specrails_chat(create, kind:'explore', contextScope)\` → keep the
61
+ conversation id.
62
+ - First \`send\`: text \`/specrails:explore-spec\` + blank line + the idea, with
63
+ \`lightweight: true\`, \`maxTurns: 20\`. Watch each turn by conversationId
64
+ (\`chat_done\` / \`chat_error\` are terminal).
65
+ - \`specrails_chat(spec_draft)\` reads the live structured draft the Explore
66
+ assistant maintains (title, description, labels, priority,
67
+ acceptanceCriteria, ready).
68
+ - When converged: \`specrails_specs(save_draft, conversationId)\` parks a
69
+ resumable draft ticket; \`specrails_specs(commit_draft, conversationId,
70
+ title, …)\` creates the real spec. Passing the conversationId preserves the
71
+ origin link ("Continue Explore", Contract Refine eligibility).
72
+ - \`contextScope\` flags: \`specrails\` (pipeline context), \`openspec\` (spec
73
+ history), \`full\` (whole-repo access), \`mcp\` (project .mcp.json servers),
74
+ \`userMcp\` (the user's own approved MCP servers), \`contractRefine\` (append
75
+ a Contract Layer after commit).
76
+ An EMBEDDED agent may instead run the refinement conversation ITSELF (no
77
+ nested AI spawn, no extra cost) and persist via path 3 — use the app's
78
+ Explore when the user wants the draft visible and resumable in the UI.
79
+ 3. **Direct insert (no AI)** — for a COMPLETE spec you already hold:
80
+ - \`specrails_specs(commit_draft)\` with NO \`conversationId\`/\`draftTicketId\`
81
+ is the canonical rich insert: \`title\` (required), \`description\`,
82
+ \`acceptanceCriteria\` (folded into an \`## Acceptance Criteria\` section),
83
+ \`priority\`, \`labels\`, \`shortSummary\` (max 240 chars). One write call.
84
+ - \`specrails_specs(from_prompt)\` stores a description verbatim but CANNOT
85
+ set acceptanceCriteria or shortSummary — prefer \`commit_draft\` for
86
+ structured specs.
87
+ - Follow with \`update\` for assignee/prerequisites/metadata when needed.
88
+ - Never route an already-refined spec through \`create\`/\`generate\` — they
89
+ REGENERATE the content with AI.
90
+
91
+ A complete spec matches the app-generated shape: short imperative English
92
+ \`title\`; one-sentence \`shortSummary\`; a \`description\` with the sections
93
+ \`## Problem Statement\`, \`## Proposed Solution\`, \`## Out of Scope\`,
94
+ \`## Technical Considerations\`, \`## Estimated Complexity\`; a separate
95
+ \`acceptanceCriteria\` array (never duplicated inside the description; no title
96
+ heading inside the description); \`labels\`; \`priority\`. Spec content is English.
97
+
98
+ ## Running the pipeline (rails)
99
+
100
+ - Configure: \`set_tickets\` (replaces the assigned set), \`set_profile\` (null =
101
+ legacy), \`set_engine\` (null = project primary), \`set_name\`.
102
+ - Launch modes:
103
+ - \`implement\`: one pipeline job (Architect → Developer → Reviewer → Ship)
104
+ over the rail's tickets.
105
+ - \`batch-implement\`: dependency-aware waves across many tickets.
106
+ - Freestyle (wire value \`ultracode\`): hands the spec straight to the model —
107
+ one job per ticket; Claude-only; \`model\` picker; optional
108
+ \`interactive\` in-job chat (settle with \`specrails_jobs(finalize)\`).
109
+ - \`loop\`: runs a published loop graph per ticket (\`loopId\`,
110
+ \`reasoning_effort\`).
111
+ - Profiles are Claude-only: a profile set on a rail that is then pointed at
112
+ codex/gemini is force-nulled.
113
+ - \`stop\` kills the rail's process tree AND cancels its queued jobs
114
+ (destructive).
115
+ - \`specrails_jobs(spawn, command)\` bypasses rails and enqueues an arbitrary
116
+ slash-command job (e.g. \`/specrails:implement #5 --yes\`); \`queue\`, \`pause\`,
117
+ \`resume\`, \`reorder\`, \`priority\` manage the queue.
118
+
39
119
  ## Async results (IMPORTANT)
40
120
 
41
121
  Cost-incurring / streaming actions (launch a rail, generate a spec, send a chat
42
- turn, refine an agent, SMASH) return immediately with a reference (jobId /
43
- requestId) and emit their REAL result over the WebSocket bus. To get the actual
44
- outcome, call \`specrails_watch\` with the returned reference; it waits for the
45
- operation to settle and returns the final result. Do not assume success from the
46
- acceptance alone.
122
+ turn, refine an agent, SMASH, install a plugin) return 202 immediately with a
123
+ reference (jobId / conversationId / requestId) and emit the REAL result over
124
+ the app's event bus. \`specrails_watch(projectId, ref, untilMs)\` waits for the
125
+ operation to settle. Rules:
126
+
127
+ - \`projectId\` is REQUIRED on watch — it does not default to the active project.
128
+ - Default \`untilMs\` is 120000 (max 600000); rails routinely run longer.
129
+ - \`settled:false\` means TIMEOUT, not failure: the operation may still be
130
+ running, or may have finished without a watch-terminal event. Re-watch with a
131
+ larger window or poll the domain read to confirm: \`specrails_jobs(get)\`,
132
+ \`specrails_specs(get)\`, \`specrails_plugins(health)\`.
133
+ - Chat turns are watched by conversationId (\`chat_done\` / \`chat_error\`).
134
+
135
+ Never assume success from the 202 acceptance alone.
136
+
137
+ ## Permissions — two regimes
138
+
139
+ - **External MCP clients** (Claude Desktop, Cursor, …): four INDEPENDENT opt-in
140
+ tiers configured by the user in the app's Settings ▸ MCP — Read (always on),
141
+ Write, AI-spawn (costs money), Destructive. On refusal, tell the user to
142
+ enable the named tier in Settings ▸ MCP.
143
+ - **The in-app agent chat**: a CUMULATIVE ladder the user steers live with
144
+ Shift+Tab — observe (read) ▸ edit (+write) ▸ operate (+ai-spawn) ▸ autonomous
145
+ (+destructive). It overrides the Settings checkboxes for that chat. On
146
+ refusal, tell the user to raise the level with Shift+Tab.
47
147
 
48
- ## Permission tiers
148
+ Tools cannot raise their own permissions in either regime. Common tiers:
149
+ list/get/spending/watch = read; commit_draft, from_prompt, update, set_tickets,
150
+ plugin install, Jira connect = write; spec create/generate, rail launch, chat
151
+ send, job spawn = ai-spawn; spec delete, rail stop, job purge, plugin
152
+ uninstall, Jira disconnect, project unregister = destructive. Note the
153
+ embedded spec-refinement happy path (investigate + commit_draft) needs only
154
+ read + write — ai-spawn is required only to launch work or spawn a nested AI.
49
155
 
50
- The server enforces four opt-in tiers, configured by the user in Settings ▸ MCP:
51
- - **Read** (always on): queries + resources.
52
- - **Write**: create/edit specs, settings, rail config.
53
- - **AI-spawn**: actions that spawn an AI CLI and cost money.
54
- - **Destructive**: delete data, kill processes, mutate external systems.
156
+ ## Providers & Claude-only surface
55
157
 
56
- If a tool is refused, the error names the tier the user must enable. Relay that
57
- to the user rather than retrying blindly.
158
+ - Installed providers are per-project; AI-spawning calls may pick any installed
159
+ one (\`aiEngine\`); rails carry a per-rail engine.
160
+ - CLAUDE-ONLY: agent profiles, Contract Refine, SMASH, Freestyle mode
161
+ (\`ultracode\`), interactive jobs. They are rejected or inert when the
162
+ effective engine is codex or gemini.
163
+ - Cost figures are authoritative for claude and estimated for codex/gemini
164
+ (flagged as estimated in analytics).
58
165
 
59
- ## Claude-only features
166
+ ## Domain cheat-sheet
60
167
 
61
- Agent profiles, Contract Refine, and SMASH are Claude-only. They are unavailable
62
- (and rejected) on projects whose selected provider is Codex or Gemini.
168
+ - **Epics / SMASH** (\`specrails_specs\`): \`smash\` splits a large spec into child
169
+ specs (Claude-only); \`smash_undo\` restores (needs the \`smashedAt\` stamp);
170
+ \`delete_epic_children\` removes a whole family.
171
+ - **Attachments**: \`list_attachments\` / \`get_attachment\` read files the user
172
+ attached in the app UI; \`generate\` / \`ai_edit\` accept \`attachmentIds\`.
173
+ Uploading new attachments is not available over MCP.
174
+ - **Jira** (\`specrails_jira\`): per-project connection (the token stays
175
+ on-device). Jira-backed specs carry a LOCAL numeric id — never a \`PROJ-123\`
176
+ key; map via \`links\`. Status write-back flows through a durable outbox
177
+ (\`outbox\`, \`retry_outbox\`).
178
+ - **Code explorer** (\`specrails_code\`): read-only repo browsing — \`tree\`
179
+ (provenance: which specs/jobs touched each file), \`read_file\`, \`summary\`,
180
+ \`provenance\`, \`diff\`. There is no MCP write path to files.
181
+ - **Analytics** (\`specrails_analytics\`): \`spending\` aggregates by surface
182
+ (\`job\`, \`quick-spec\`, \`explore-spec\`, \`ai-edit\`, \`file-summary\`), model,
183
+ ticket, day. Prefer \`spending\` over raw \`invocations\`/\`export\` for token
184
+ economy. TWO budget knobs exist: \`specrails_analytics(budget_set,
185
+ dailyBudgetUsd)\` is PER-PROJECT and pauses that project's queue when
186
+ exceeded; \`specrails_settings(set, dailyBudgetUsd)\` is the APP-WIDE budget.
187
+ - **Plugins** (\`specrails_plugins\`): per-project MCP integrations; \`preview\`
188
+ the diff before \`install\`; a degraded plugin never blocks rail launches.
189
+ - **Profiles** (\`specrails_agents\`): per-project agent chains; the baseline
190
+ trio \`sr-architect\`/\`sr-developer\`/\`sr-reviewer\` is required; routing rules
191
+ end in a single terminal \`default: true\` rule; requires specrails-core
192
+ 4.1.0 or newer.
193
+ - **Setup** (\`specrails_setup\`): \`prerequisites\` → \`add_project\` →
194
+ \`install_config\` per provider → ONE \`install\` (provisions all chosen
195
+ providers; quick-only, offline) → poll \`checkpoints\` until
196
+ \`isInstalling === false\`.
197
+ - **Loops lifecycle** (\`specrails_loops\`): Draft → \`publish\` (graph-validated)
198
+ → runnable; \`update\` reverts to Draft and returns 409 while running;
199
+ \`preview\` dry-runs token resolution without spawning; constants are shared
200
+ values graphs reference.
63
201
 
64
- ## Typical workflow
202
+ ## Operating discipline
65
203
 
66
- 1. \`specrails_projects(list)\` → pick a project; \`specrails_select_project\`.
67
- 2. \`specrails_specs(list)\` → inspect the backlog. To ADD a spec from a user
68
- request, use \`specrails_specs(action:'create')\` — it routes through **Quick
69
- Add Spec**: the specrails agent generates a structured spec with AI from the
70
- request, exactly like the app's "Add Spec" button (so MCP-created specs are
71
- indistinguishable from UI-created ones). It is async — watch the returned ref
72
- with \`specrails_watch\`. Use \`from_prompt\` only to store a finished spec verbatim.
73
- 3. \`specrails_rails(set_tickets)\` then \`specrails_rails(launch)\` → run the pipeline;
74
- \`specrails_watch\` the returned jobId.
75
- 4. \`specrails_analytics(spending)\` → review cost.
204
+ - Do not mutate statuses the pipeline manages (\`in_progress\`/\`done\` transitions
205
+ ride job outcomes).
206
+ - Confirm cost-incurring (ai-spawn) and destructive actions with the user
207
+ first, with cost/risk framing.
208
+ - Report ids and results verbatim; never fabricate outcomes.
209
+ - Use \`specrails_search\` / \`specrails_describe\` to discover the exact action
210
+ and arguments instead of guessing.
76
211
 
77
212
  ## Resources
78
213
 
79
- Read-only state is also exposed as MCP resources: \`specrails://projects\`,
80
- \`specrails://projects/{id}/tickets\`, \`specrails://projects/{id}/rails\`,
81
- \`specrails://projects/{id}/analytics\`, and \`specrails://guide\` (this document).
214
+ Read-only state is also exposed as MCP resources: \`specrails://guide\` (this
215
+ document), \`specrails://projects\` (all registered projects), and
216
+ \`specrails://projects/{projectId}\` (one project by id).
82
217
  `;
@@ -91,7 +91,7 @@ function analyticsTools() {
91
91
  .number()
92
92
  .nullable()
93
93
  .optional()
94
- .describe('budget_set: daily budget cap USD (>0); null clears it'),
94
+ .describe('budget_set: daily budget cap USD (>0); null clears it. PER-PROJECT daily cap — pauses this project\'s queue when exceeded. For the app-wide budget across all projects use specrails_settings.'),
95
95
  jobCostThresholdUsd: zod_1.z
96
96
  .number()
97
97
  .nullable()
@@ -15,16 +15,31 @@ function appTools() {
15
15
  {
16
16
  name: 'specrails_settings',
17
17
  title: 'App settings',
18
- description: 'Read or update app-level Specrails settings (theme, language, daily budget, cost-alert threshold). ' +
19
- 'Actions: get, set. The MCP enable flag and permission tiers are read-only here (user-controlled in the app).',
18
+ description: 'Read or update app-level Specrails settings (theme, language, daily budget, cost-alert threshold, Code Explorer summary language + monthly summary budget). ' +
19
+ 'Actions: get, set. The MCP enable flag and permission tiers are read-only here (user-controlled in the app). ' +
20
+ 'dailyBudgetUsd here is APP-WIDE (all projects combined); per-project caps live in specrails_analytics(budget_set).',
20
21
  hintTier: 'read',
21
22
  tier: (args) => (args.action === 'set' ? 'write' : 'read'),
22
23
  inputSchema: {
23
24
  action: zod_1.z.enum(['get', 'set']).describe('Operation'),
24
25
  theme: zod_1.z.enum(WRITABLE_THEMES).optional(),
25
26
  language: zod_1.z.enum(WRITABLE_LANGS).optional(),
26
- dailyBudgetUsd: zod_1.z.number().min(0).nullable().optional(),
27
+ dailyBudgetUsd: zod_1.z
28
+ .number()
29
+ .min(0)
30
+ .nullable()
31
+ .optional()
32
+ .describe('APP-WIDE daily budget cap USD across all projects; null clears it. Per-project caps live in specrails_analytics(budget_set).'),
27
33
  costAlertThresholdUsd: zod_1.z.number().min(0).nullable().optional(),
34
+ summaryLanguage: zod_1.z
35
+ .enum(['en', 'es'])
36
+ .optional()
37
+ .describe('Code Explorer file-summary language (app-wide)'),
38
+ summaryMonthlyBudgetUsd: zod_1.z
39
+ .number()
40
+ .min(0)
41
+ .optional()
42
+ .describe('Code Explorer monthly AI file-summary budget in USD (app-wide, default 5)'),
28
43
  },
29
44
  handler: (ctx, args) => {
30
45
  const db = ctx.desktopDb;
@@ -34,6 +49,9 @@ function appTools() {
34
49
  language: (0, desktop_db_1.getDesktopSetting)(db, 'ui_language') ?? null,
35
50
  dailyBudgetUsd: num((0, desktop_db_1.getDesktopSetting)(db, 'desktop_daily_budget_usd')),
36
51
  costAlertThresholdUsd: num((0, desktop_db_1.getDesktopSetting)(db, 'cost_alert_threshold_usd')),
52
+ // Code Explorer settings (same keys + defaults as GET /api/code-explorer-settings)
53
+ summaryLanguage: (0, desktop_db_1.getDesktopSetting)(db, 'summary_language') === 'es' ? 'es' : 'en',
54
+ summaryMonthlyBudgetUsd: nonNegNum((0, desktop_db_1.getDesktopSetting)(db, 'summary_monthly_budget_usd')) ?? 5.0,
37
55
  mcp: {
38
56
  enabled: (0, mcp_tiers_1.isMcpEnabled)(db),
39
57
  tierWrite: (0, mcp_tiers_1.isTierEnabled)(db, 'write'),
@@ -60,8 +78,25 @@ function appTools() {
60
78
  writeNumOrClear(db, 'cost_alert_threshold_usd', args.costAlertThresholdUsd);
61
79
  changed.push('costAlertThresholdUsd');
62
80
  }
63
- if (!changed.length)
64
- throw new Error('set requires at least one field (theme, language, dailyBudgetUsd, costAlertThresholdUsd).');
81
+ // Code Explorer settings — same validation as PATCH /api/code-explorer-settings.
82
+ if (args.summaryLanguage !== undefined) {
83
+ if (args.summaryLanguage !== 'en' && args.summaryLanguage !== 'es') {
84
+ throw new Error("summaryLanguage must be one of: 'en', 'es'.");
85
+ }
86
+ (0, desktop_db_1.setDesktopSetting)(db, 'summary_language', args.summaryLanguage);
87
+ changed.push('summaryLanguage');
88
+ }
89
+ if (args.summaryMonthlyBudgetUsd !== undefined) {
90
+ const v = args.summaryMonthlyBudgetUsd;
91
+ if (typeof v !== 'number' || !Number.isFinite(v) || v < 0) {
92
+ throw new Error('summaryMonthlyBudgetUsd must be a non-negative number.');
93
+ }
94
+ (0, desktop_db_1.setDesktopSetting)(db, 'summary_monthly_budget_usd', String(v));
95
+ changed.push('summaryMonthlyBudgetUsd');
96
+ }
97
+ if (!changed.length) {
98
+ throw new Error('set requires at least one field (theme, language, dailyBudgetUsd, costAlertThresholdUsd, summaryLanguage, summaryMonthlyBudgetUsd).');
99
+ }
65
100
  return { ok: true, changed };
66
101
  },
67
102
  },
@@ -73,6 +108,11 @@ function num(v) {
73
108
  const n = Number(v);
74
109
  return Number.isFinite(n) ? n : null;
75
110
  }
111
+ /** Mirror of the code-explorer-settings route parsing: finite AND >= 0, else null. */
112
+ function nonNegNum(v) {
113
+ const n = num(v);
114
+ return n !== null && n >= 0 ? n : null;
115
+ }
76
116
  function writeNumOrClear(db, key, value) {
77
117
  if (value === null)
78
118
  (0, desktop_db_1.setDesktopSetting)(db, key, '');
@@ -19,7 +19,12 @@ function chatTools() {
19
19
  name: 'specrails_chat',
20
20
  title: 'Chat / Explore',
21
21
  description: 'Manage a project\'s chat & Explore-Spec conversations and drive their AI turns. ' +
22
+ 'EXPLORE RECIPE: create(kind:\'explore\', contextScope) → send the bootstrap text "/specrails:explore-spec\\n\\n<idea>" ' +
23
+ 'with {lightweight:true, maxTurns:20} → watch chat_done per turn → spec_draft to read the accumulated draft → ' +
24
+ 'persist via specrails_specs(commit_draft, conversationId=<this conversation>) which preserves origin linkage, ' +
25
+ 'Contract Refine and "Continue Explore". NOTE: spec_draft state is in-memory; it returns {draft:null} after a server restart. ' +
22
26
  'Actions: list_conversations, get (conversation + messages), create (kind sidebar|explore, optional provider/model/contextScope), ' +
27
+ 'update (rename title / change model), ' +
23
28
  'send (cost-incurring — spawns the AI CLI and streams the reply async over WS), abort (interrupt the in-flight turn), ' +
24
29
  'delete (destructive — removes the conversation, its messages, and clears linked draft origin), minimize (arm Explore idle-kill timer), ' +
25
30
  'restore (cancel the idle-kill timer), spec_draft (read the in-memory Explore spec-draft state), messages (persisted history only).',
@@ -59,7 +64,9 @@ function chatTools() {
59
64
  contextScope: zod_1.z
60
65
  .record(zod_1.z.unknown())
61
66
  .optional()
62
- .describe('Explore-only context scope flags for create (mcp/userMcp/full/specrails/openspec/contractRefine)'),
67
+ .describe('Explore-only context scope flags for create: {full: repo-wide investigation, specrails: specs context, ' +
68
+ 'openspec: openspec context, mcp: load project .mcp.json (spawns from repo cwd, slower), ' +
69
+ "userMcp: user's approved MCP servers, contractRefine: append Contract Layer on commit}"),
63
70
  // update params
64
71
  title: zod_1.z.string().optional().describe('New title for update'),
65
72
  // send params
@@ -127,7 +134,7 @@ function chatTools() {
127
134
  return {
128
135
  ...r,
129
136
  conversationId: requireConv(),
130
- hint: `Turn accepted (202). The assistant reply streams over WebSocket — use specrails_watch with conversationId "${requireConv()}" to await completion (chat_done / chat_error).`,
137
+ hint: `Turn accepted (202). The assistant reply streams over WebSocket — use specrails_watch with conversationId "${requireConv()}" to await completion (chat_done / chat_error). Each send spawns a fresh AI CLI turn (cost); Explore turns accumulate the spec_draft.`,
131
138
  };
132
139
  }
133
140
  case 'abort':
@@ -11,8 +11,9 @@ const types_1 = require("./types");
11
11
  *
12
12
  * Every op is per-project under `/api/projects/:projectId/code/*`. The v1 edit
13
13
  * path (PUT /code/file) is intentionally NOT exposed — Code Explorer is
14
- * read-only here. The app-level GET/PATCH /api/code-explorer-settings ops are
15
- * app-scoped settings, surfaced by the settings domain, not here.
14
+ * read-only here. The app-level code-explorer settings (summary language +
15
+ * monthly summary budget) are surfaced by specrails_settings
16
+ * (summaryLanguage / summaryMonthlyBudgetUsd), not here.
16
17
  *
17
18
  * Encode query strings explicitly so file paths with spaces/`#`/`?` survive.
18
19
  */
@@ -23,10 +23,11 @@ function jobsTools() {
23
23
  'cancel (destructive — cancels a running/queued job or deletes a terminal one), ' +
24
24
  'purge (destructive — bulk-delete persisted job rows in a date range), ' +
25
25
  'pause / resume (queue), reorder (queued-job order), priority (change a queued job\'s priority), ' +
26
- 'compare (two jobs side-by-side), export (up to 10k rows as JSON/CSV), ' +
26
+ 'compare (two jobs side-by-side), export (up to 10k rows as JSON/CSV — inlines everything; prefer list/stats for token economy), ' +
27
27
  'diagnostic (binary ZIP — returns a note, not the bytes), run_state (project run state), ' +
28
+ 'pipeline (read a pipeline\'s jobs + statuses — use after composing dependent spawns), ' +
28
29
  'activity (recent activity feed), stats, metrics, default_spec_model, ' +
29
- 'interactive_turn (ai-spawn — send one more prompt to a running interactive ultracode job), ' +
30
+ 'interactive_turn (ai-spawn — send one more prompt to a running interactive Freestyle/ultracode job), ' +
30
31
  'finalize (finalize a running interactive job).',
31
32
  hintTier: 'read',
32
33
  tier: (a) => {
@@ -56,6 +57,7 @@ function jobsTools() {
56
57
  'export',
57
58
  'diagnostic',
58
59
  'run_state',
60
+ 'pipeline',
59
61
  'activity',
60
62
  'stats',
61
63
  'metrics',
@@ -84,7 +86,7 @@ function jobsTools() {
84
86
  .optional()
85
87
  .describe('Priority for spawn / priority action'),
86
88
  dependsOnJobId: zod_1.z.string().optional().describe('Make the spawned job depend on this job id'),
87
- pipelineId: zod_1.z.string().optional().describe('Group the spawned job into this pipeline'),
89
+ pipelineId: zod_1.z.string().optional().describe('Pipeline id: group the spawned job into this pipeline (spawn) / pipeline to read (pipeline)'),
88
90
  profileName: zod_1.z
89
91
  .string()
90
92
  .optional()
@@ -143,7 +145,7 @@ function jobsTools() {
143
145
  });
144
146
  return {
145
147
  ...r,
146
- hint: 'Spawned an AI CLI job (incurs token cost). Use specrails_watch with the returned jobId to await completion.',
148
+ hint: 'Spawned an AI CLI job (incurs token cost). Use specrails_jobs(get, jobId) to poll status; specrails_watch settles for this jobId via its 5s job-status poll fallback (terminal events stream only for rail-launched or interactive jobs).',
147
149
  };
148
150
  }
149
151
  case 'cancel': {
@@ -191,7 +193,11 @@ function jobsTools() {
191
193
  qs.set('from', args.from);
192
194
  if (args.to)
193
195
  qs.set('to', args.to);
194
- return (0, types_1.apiCall)(ctx, 'GET', `${base}/jobs/export?${qs.toString()}`);
196
+ const data = await (0, types_1.apiCall)(ctx, 'GET', `${base}/jobs/export?${qs.toString()}`);
197
+ return {
198
+ note: 'Inlines up to 10k rows — prefer list/stats for token economy.',
199
+ data,
200
+ };
195
201
  }
196
202
  case 'diagnostic': {
197
203
  const id = args.jobId;
@@ -210,6 +216,12 @@ function jobsTools() {
210
216
  }
211
217
  case 'run_state':
212
218
  return (0, types_1.apiCall)(ctx, 'GET', `${base}/state`);
219
+ case 'pipeline': {
220
+ const id = args.pipelineId;
221
+ if (!id)
222
+ throw new Error('pipeline requires a "pipelineId".');
223
+ return (0, types_1.apiCall)(ctx, 'GET', `${base}/pipelines/${encodeURIComponent(id)}`);
224
+ }
213
225
  case 'activity': {
214
226
  const qs = new URLSearchParams();
215
227
  if (args.limit !== undefined)
@@ -240,7 +252,7 @@ function jobsTools() {
240
252
  const r = await (0, types_1.apiCall)(ctx, 'POST', `${base}/jobs/${encodeURIComponent(id)}/messages`, { text });
241
253
  return {
242
254
  ...r,
243
- hint: 'Queued an additional interactive turn (incurs token cost). Use specrails_watch with the jobId to follow the job.',
255
+ hint: 'Queued an additional interactive turn (incurs token cost). specrails_watch settles when the whole job finalizes; a single turn\'s completion arrives as job.turn_done in the events array.',
244
256
  };
245
257
  }
246
258
  case 'finalize': {
@@ -7,11 +7,16 @@ const types_1 = require("./types");
7
7
  * Loops — the GLOBAL (cross-project) visual loop-builder library. Routes live at
8
8
  * `/api/loops*` and `/api/loop-templates` (NOT under `/projects` — no projectId).
9
9
  * Gated server-side by SPECRAILS_LOOPS_SECTION (every route 404s when off).
10
+ * Exception: the standalone run actions (`run` / `run_get`) ARE project-scoped
11
+ * (`/api/projects/:projectId/loop-runs*`) — a ticket-less loop runs directly
12
+ * against a project with no rail and no ticket.
10
13
  *
11
14
  * A single domain-facade tool with an `action` enum and a dynamic tier:
12
- * - read: list, get, templates, factory, commands, constants_list, preview
15
+ * - read: list, get, templates, factory, commands, constants_list,
16
+ * preview, run_get
13
17
  * - write: constant_create, constant_update, import, create, from_template,
14
18
  * fork, update, publish, unpublish, duplicate
19
+ * - ai-spawn: run (spawns an AI CLI, incurs cost, async 202)
15
20
  * - destructive: constant_delete, delete
16
21
  */
17
22
  function loopsTools() {
@@ -20,7 +25,9 @@ function loopsTools() {
20
25
  name: 'specrails_loops',
21
26
  title: 'Loops',
22
27
  description: 'Manage the global (cross-project) loop library and its templates/factory/constants. ' +
23
- 'Loops are visual builder graphs reused across projects; this is an APP-LEVEL domain (no projectId). ' +
28
+ 'Loops are visual builder graphs reused across projects; this is an APP-LEVEL domain (no projectId, except the run actions). ' +
29
+ 'To RUN a loop on a project\'s tickets: publish it, then specrails_rails(launch, mode:\'loop\', loopId=…). ' +
30
+ 'For a standalone ticket-less run use the run action. ' +
24
31
  'Actions: ' +
25
32
  'list (all saved loops), ' +
26
33
  'get (one loop by id), ' +
@@ -37,12 +44,16 @@ function loopsTools() {
37
44
  'update (name/description/graph — reverts to Draft, 409 while running), ' +
38
45
  'publish (graph-validated), unpublish (409 while running), ' +
39
46
  'duplicate (copy a loop), ' +
40
- 'delete (destructive — 409 while running).',
47
+ 'delete (destructive — 409 while running), ' +
48
+ 'run (ai-spawn — standalone ticket-less run of a Published loop against a project: spawns an AI CLI, incurs token cost, returns 202 with loopRunId), ' +
49
+ 'run_get (read one loop run\'s live/terminal state — the post-timeout recovery read).',
41
50
  hintTier: 'read',
42
51
  tier: (a) => {
43
52
  const action = a.action;
44
53
  if (action === 'delete' || action === 'constant_delete')
45
54
  return 'destructive';
55
+ if (action === 'run')
56
+ return 'ai-spawn';
46
57
  if ([
47
58
  'constant_create',
48
59
  'constant_update',
@@ -81,9 +92,16 @@ function loopsTools() {
81
92
  'unpublish',
82
93
  'duplicate',
83
94
  'delete',
95
+ 'run',
96
+ 'run_get',
84
97
  ])
85
98
  .describe('Operation to perform'),
86
- loopId: zod_1.z.string().optional().describe('Loop id (for get / update / publish / unpublish / duplicate / delete)'),
99
+ projectId: zod_1.z
100
+ .string()
101
+ .optional()
102
+ .describe('Project id (run / run_get only — defaults to the active project; ignored by every other action)'),
103
+ loopId: zod_1.z.string().optional().describe('Loop id (for get / update / publish / unpublish / duplicate / delete / run — must be Published for run)'),
104
+ loopRunId: zod_1.z.string().optional().describe('Loop run id (for run_get — returned by run)'),
87
105
  constantId: zod_1.z.string().optional().describe('Constant id (for constant_update / constant_delete)'),
88
106
  templateId: zod_1.z.string().optional().describe('Template id (for from_template)'),
89
107
  factoryId: zod_1.z.string().optional().describe('Factory loop id (for fork)'),
@@ -97,7 +115,18 @@ function loopsTools() {
97
115
  .optional()
98
116
  .describe('Loop graph object { nodes, edges, ... } (for create / update; required for preview)'),
99
117
  value: zod_1.z.string().optional().describe('Constant value (for constant_create / constant_update)'),
100
- provider: zod_1.z.string().optional().describe('Provider for token resolution in preview (default "claude")'),
118
+ provider: zod_1.z
119
+ .string()
120
+ .optional()
121
+ .describe('Provider for token resolution in preview (default "claude") / AI engine for run (must be installed on the project; default = project primary)'),
122
+ model: zod_1.z
123
+ .string()
124
+ .optional()
125
+ .describe('Model for run — validated against the chosen provider\'s catalog; omit for the provider default'),
126
+ reasoning_effort: zod_1.z
127
+ .enum(['low', 'medium', 'high'])
128
+ .optional()
129
+ .describe('Reasoning-effort tier for run'),
101
130
  loops: zod_1.z.array(zod_1.z.unknown()).optional().describe('Array of loop export envelopes (for import)'),
102
131
  },
103
132
  async handler(ctx, args) {
@@ -214,6 +243,29 @@ function loopsTools() {
214
243
  ...(args.name !== undefined ? { name: args.name } : {}),
215
244
  });
216
245
  }
246
+ // ── Standalone runs (project-scoped) ────────────────────────────────
247
+ case 'run': {
248
+ if (!loopId)
249
+ throw new Error('run requires a "loopId" (the loop must be Published).');
250
+ const base = (0, types_1.projectPath)(ctx, args.projectId);
251
+ const r = await (0, types_1.apiCall)(ctx, 'POST', `${base}/loop-runs`, {
252
+ loopId,
253
+ ...(args.provider !== undefined ? { provider: args.provider } : {}),
254
+ ...(args.model !== undefined ? { model: args.model } : {}),
255
+ ...(args.reasoning_effort !== undefined ? { reasoning_effort: args.reasoning_effort } : {}),
256
+ });
257
+ return {
258
+ ...r,
259
+ hint: 'Run accepted (202). Use specrails_watch with the returned loopRunId (loop.run_completed / loop.run_stopped are terminal), or poll specrails_loops(run_get, loopRunId) after a timeout.',
260
+ };
261
+ }
262
+ case 'run_get': {
263
+ const loopRunId = args.loopRunId;
264
+ if (!loopRunId)
265
+ throw new Error('run_get requires a "loopRunId".');
266
+ const base = (0, types_1.projectPath)(ctx, args.projectId);
267
+ return (0, types_1.apiCall)(ctx, 'GET', `${base}/loop-runs/${encodeURIComponent(loopRunId)}`);
268
+ }
217
269
  // ── Destructive ─────────────────────────────────────────────────────
218
270
  case 'delete': {
219
271
  if (!loopId)