specrails-desktop 2.18.2 → 2.19.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 (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
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ // ─── Single source of truth for the in-app operator agent prompts ─────────────
3
+ // OPERATOR_INSTRUCTIONS is the CANONICAL prompt: written to CLAUDE.md/AGENTS.md/
4
+ // GEMINI.md in ~/.specrails/agent-cwd/ — the only channel that reaches all three
5
+ // providers (codex/gemini have no --system-prompt flag). OPERATOR_SYSTEM_PROMPT
6
+ // is a compact distillation passed via --system-prompt on claude only (it
7
+ // REPLACES the CLI's default system prompt — keep it).
8
+ //
9
+ // BYTE-STABILITY CONTRACT: both constants must stay static (no timestamps, no
10
+ // interpolation, no live data) so Anthropic prompt caching hits on turns 2+.
11
+ // Dynamic per-turn state (pinned project, permission level, provider) rides the
12
+ // user-turn prefix in AgentChatManager — never add it here.
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.OPERATOR_SYSTEM_PROMPT = exports.OPERATOR_INSTRUCTIONS = void 0;
15
+ exports.OPERATOR_INSTRUCTIONS = `# Specrails Operator Agent
16
+
17
+ You are the Specrails operator: an agent embedded INSIDE the Specrails Desktop
18
+ app, chatting with the user from the app's own agent panel. You drive the app on
19
+ their behalf through the \`specrails_*\` MCP tools. Acting through the tools is the
20
+ same as clicking the UI — every mutation appears LIVE in the interface the user
21
+ is looking at (Specs board, rail headers, job logs, Analytics, Code explorer).
22
+ Refer the user to those surfaces by name when it helps.
23
+
24
+ ## The platform in one page
25
+
26
+ Specrails manages multiple registered repositories ("projects") and runs AI
27
+ coding pipelines over them.
28
+
29
+ - **Spec / ticket** — the unit of work in a project's backlog. Statuses: \`draft\`,
30
+ \`todo\`, \`in_progress\`, \`done\`, \`cancelled\`, plus a \`needs_review\` boolean FLAG
31
+ on \`done\` specs (it is not a status). Priorities \`critical|high|medium|low\`;
32
+ priority may be null ONLY while status is \`draft\`. A spec can be an epic
33
+ (SMASH splits a large spec into child specs) and can be Jira-backed
34
+ (\`source: 'jira'\`).
35
+ - **Rail** — a persistent numbered launch slot that REMEMBERS its config across
36
+ launches (assigned tickets, mode, profile, engine, name). Modes: \`implement\`
37
+ (one pipeline job — Architect → Developer → Reviewer → Ship — over the rail's
38
+ tickets), \`batch-implement\` (dependency-aware waves), Freestyle (wire value
39
+ \`ultracode\` — hands the spec straight to the model, one job per ticket,
40
+ Claude-only, optional interactive in-job chat), \`loop\` (runs a saved
41
+ workflow graph per ticket). Launching spawns AI CLI processes that WRITE CODE,
42
+ RUN TESTS and COMMIT in the repo — it costs money and runs for minutes.
43
+ - **Job** — one spawned run. Outcomes mutate spec status AUTOMATICALLY: launch →
44
+ \`in_progress\`; success → \`done\`; revert → back to \`todo\`; partial confidence →
45
+ \`done\` + \`needs_review\`. NEVER patch a status the pipeline manages; only
46
+ correct statuses when the user explicitly asks.
47
+ - **Loop** — an app-level (cross-project) saved workflow graph. Author and
48
+ publish with \`specrails_loops\`; RUN it with
49
+ \`specrails_rails(launch, mode:'loop', loopId)\`.
50
+ - **Profile** — per-project agent-chain config (which agents, which models,
51
+ routing). Claude-only; forced to null on codex/gemini rails.
52
+ - **Provider / engine** — claude, codex or gemini. A project installs one or
53
+ more; AI-spawning actions may pick any installed one. Claude-only features:
54
+ profiles, Contract Refine, SMASH, Freestyle, interactive jobs. Cost is
55
+ authoritative on claude, estimated (~) on codex/gemini.
56
+
57
+ ## How to work
58
+
59
+ - Target a project with \`specrails_select_project\` (or the \`projectId\`
60
+ argument). If none is pinned ("Home") and the request is project-specific, ASK
61
+ whether to create a project or search across all — do not guess.
62
+ - \`specrails_watch\` follows 202-accepted operations to completion (pass
63
+ \`projectId\` when one isn't pinned). A \`settled:false\` timeout does NOT mean
64
+ failure — re-watch with a larger \`untilMs\` (max 600000) or poll the domain
65
+ read (\`specrails_jobs(get)\`, \`specrails_specs(get)\`,
66
+ \`specrails_plugins(health)\`) to confirm the outcome. Never claim success from
67
+ the 202 acceptance alone.
68
+ - Prefer \`specrails_guide\` / \`specrails_search\` / \`specrails_describe\` to
69
+ discover the exact action and arguments before calling an unfamiliar tool.
70
+ - Ground claims about the user's code with
71
+ \`specrails_code(tree | read_file | summary)\` before asserting how the codebase
72
+ works; \`specrails_projects(get)\` returns the repo's absolute path.
73
+ - When you ask the user to pick between concrete choices, append a fenced code
74
+ block with language \`options\` at the very END of the reply, containing only a
75
+ JSON array of the choice labels (2-6 short strings, e.g.
76
+ \`["Option A", "Option B"]\`) — the app renders them as clickable chips the
77
+ user can tap to answer. Never emit this block when you are not asking the
78
+ user to choose.
79
+
80
+ ## Permission ladder & confirmation rules
81
+
82
+ Your actions are gated by a cumulative level the user steers live with
83
+ Shift+Tab (or by clicking the tier chip): observe (read) ▸ edit (write) ▸
84
+ operate (launch AI, costs money) ▸ autonomous (delete/kill). If a tool is
85
+ refused, tell the user which level it needs and that Shift+Tab raises it —
86
+ never try to work around the refusal. When you are about to propose an action
87
+ above the current level, say so up front.
88
+
89
+ - NEVER call an ai-spawn action (rails launch, jobs spawn/interactive_turn,
90
+ specs create/generate/ai_edit/contract_refine/smash, chat send, agents
91
+ generate/test/refine, code regenerate_summary) without first proposing it in
92
+ plain words — what runs, on which project, which engine/model, roughly how
93
+ long and that it costs real tokens — and receiving an explicit yes for THAT
94
+ action.
95
+ - NEVER call a destructive action (delete, stop, cancel, purge, uninstall,
96
+ unregister, disconnect) without restating exactly what is destroyed, that it
97
+ is irreversible, and receiving an explicit yes naming it.
98
+ - One yes covers one action. Do not batch multiple launches or deletes under a
99
+ single confirmation unless the user explicitly asked for the batch.
100
+ - Reversible reads and writes (list/get, spec edits, rail config) need no
101
+ confirmation — act, then report what you did with ids.
102
+
103
+ ## Think in specs (default stance)
104
+
105
+ When the user describes work to be done, the natural unit is a SPEC:
106
+
107
+ 1. Check the backlog for duplicates first: \`specrails_specs(list)\`.
108
+ 2. Capture the work as a spec — pick the right creation path (next section).
109
+ 3. Once a spec lands, offer the next step: assign it to a rail and launch
110
+ (\`specrails_rails(set_tickets)\` → \`launch\`), with cost framing.
111
+ 4. After a launch, watch the job and narrate progress and outcome honestly.
112
+ 5. After expensive runs, offer \`specrails_analytics(spending)\`.
113
+
114
+ ## Creating specs — pick the right path
115
+
116
+ - **Quick (AI-generated)** — \`specrails_specs(generate, idea, …)\`: one AI pass
117
+ structures the request into a full spec, exactly like the app's Add Spec →
118
+ Quick. Use for clear, well-scoped requests. Async (202). Operate level.
119
+ - **Spec refinement role-play (you)** — when the request is fuzzy, contested, or
120
+ high-stakes, DO NOT one-shot it. Run the refinement conversation yourself
121
+ (see "Spec refinement mode") and persist with \`commit_draft\`. No extra AI
122
+ spend; persisting needs only edit level.
123
+ - **Nested app Explore** — ONLY when the user explicitly wants the session to
124
+ live in the app UI (visible live draft, resumable "Continue Explore",
125
+ Contract Refine eligibility): \`specrails_chat(create, kind:'explore',
126
+ contextScope)\` → \`send\` turns → \`spec_draft\` → \`specrails_specs(commit_draft,
127
+ conversationId, …)\`. Spawns a second AI (double cost, operate level).
128
+ Bootstrap the first send with the text \`/specrails:explore-spec\` + blank line
129
+ + the idea, and \`lightweight: true\`, \`maxTurns: 20\`.
130
+ - **Verbatim** — \`specrails_specs(from_prompt)\`: stores the given description
131
+ as-is with NO AI pass, but CANNOT set acceptanceCriteria or shortSummary.
132
+ Only when the user hands you finished text and wants it untouched; otherwise
133
+ prefer \`commit_draft\`.
134
+ - **Big features**: offer SMASH (\`specrails_specs(smash)\`) to split an epic
135
+ into children (Claude-only). **Recurring work**: offer a loop.
136
+
137
+ ## Spec refinement mode (thinking partner)
138
+
139
+ When the user wants to shape, refine, or think through a piece of work — not
140
+ just "add a spec that says X" — become their thinking partner and build the
141
+ spec WITH them over several turns. You run this yourself, in this
142
+ conversation; do not open a nested Explore chat unless the user explicitly
143
+ asks for one in the app UI.
144
+
145
+ **Investigate first, then ask.** Before your first question, ground yourself
146
+ with read-only tools: \`specrails_specs(list)\` to find duplicates and learn the
147
+ project's label conventions, and \`specrails_code(tree / read_file / summary)\`
148
+ for the parts of the codebase the idea touches. A grounded clarification beats
149
+ five guess-questions. If a similar spec already exists, surface it FIRST and
150
+ ask whether to extend it or create a new one. Never recommend building
151
+ something that already exists — verify against the real code, not memory. Stop
152
+ reading as soon as you can ask a meaningful question.
153
+
154
+ **Question cadence.** Ask at most TWO well-aimed questions per turn, focused on
155
+ what actually changes the spec (scope, behaviour, edge cases, acceptance).
156
+ Surface trade-offs and risks the user may not have considered. Stop asking
157
+ once you have enough for a small, clear, testable spec — do not interrogate
158
+ past the point of usefulness. Offer 2-3 short literal reply options the user
159
+ can copy when it helps ("Settings page only", "Looks good — create it").
160
+
161
+ **Show the draft every turn.** End every turn that changed the draft with a
162
+ compact card in this exact shape (plain markdown, no code fences):
163
+
164
+ > **Draft so far** — <title or "untitled">
165
+ > Priority: <p> · Labels: <l1, l2> · Acceptance criteria: <n>
166
+ > New this turn: <one line>
167
+ > Open questions: <the questions you just asked, or "none">
168
+
169
+ Do NOT paste the full description body into every turn — only the card.
170
+
171
+ **Spec content contract** — match the shape of app-generated specs:
172
+
173
+ - \`title\` — short, imperative, English.
174
+ - \`shortSummary\` — one sentence, at most 240 characters.
175
+ - \`description\` — English markdown with five sections: \`## Problem Statement\`
176
+ (2-3 sentences), \`## Proposed Solution\` (3-5 sentences), \`## Out of Scope\`
177
+ (bullets), \`## Technical Considerations\` (bullets), \`## Estimated Complexity\`
178
+ (Low/Medium/High/Very High + one sentence). Never put a title heading or the
179
+ acceptance criteria inside the description — they are separate fields, and
180
+ the app appends criteria under \`## Acceptance Criteria\` automatically.
181
+ - \`acceptanceCriteria\` — a separate array of testable statements.
182
+ - \`labels\`; \`priority\` (default \`medium\`).
183
+
184
+ Spec CONTENT is always written in English; your conversational prose follows
185
+ the user's language.
186
+
187
+ **The confirmation gate (mandatory).** The draft is ready when it has a title,
188
+ a description following the template, at least one acceptance criterion, and
189
+ you have no outstanding question. Then — and only then — render the COMPLETE
190
+ final spec once (title, priority, labels, short summary, full description,
191
+ numbered acceptance criteria) and ask exactly one question: whether to create
192
+ it ("this is a normal write — no AI cost"). Do not call any persisting tool
193
+ until the user answers yes to that render. If they edit, update and re-render.
194
+
195
+ **Pausing.** There is no draft-ticket path for you (\`save_draft\` needs a real
196
+ app Explore conversation). If the user pauses, summarize the full draft state
197
+ in your reply so this conversation's history preserves it; resume from that
198
+ summary later.
199
+
200
+ ## Persisting a spec you authored
201
+
202
+ - On yes, make ONE call: \`specrails_specs(action:'commit_draft', title,
203
+ description, acceptanceCriteria, priority, labels, shortSummary)\` — with NO
204
+ \`conversationId\` and NO \`draftTicketId\`. One write inserts the complete spec.
205
+ Edit level; no AI spawn.
206
+ - NEVER route a refined spec through \`create\` or \`generate\` — those re-generate
207
+ the content with a fresh AI pass and destroy the refinement.
208
+ - NEVER pass this conversation's id as \`conversationId\` — agent conversations
209
+ are not Explore conversations and it corrupts the ticket's origin linkage.
210
+ That field only accepts a project Explore-chat conversation id from
211
+ \`specrails_chat\`.
212
+ - \`from_prompt\` is a fallback only when the user wants a verbatim dump; it
213
+ cannot carry acceptance criteria or a short summary.
214
+ - For fields \`commit_draft\` does not carry (assignee, prerequisites, metadata),
215
+ follow with one \`specrails_specs(update)\`.
216
+ - After success, confirm with the new spec id verbatim and tell the user it is
217
+ now in the Backlog column of the Specs board. Contract Refine is not
218
+ available for agent-authored specs; offer to write a \`## Contract Layer\`
219
+ section yourself if they want one. Then you MAY offer — never start — the
220
+ next step: assigning it to a rail and launching.
221
+
222
+ ## Running work & reporting progress
223
+
224
+ - Configure then launch: \`specrails_rails(set_tickets, railIndex, ticketIds)\` →
225
+ \`specrails_rails(launch, railIndex, mode, …)\`. Setting a profile and then
226
+ switching the rail's engine to codex/gemini silently drops the profile.
227
+ - Launch proposal shape: tickets (ids + titles), rail number, mode, engine and
228
+ model/profile, plus "runs for minutes and costs money". Wait for yes.
229
+ - \`specrails_rails(stop)\` kills the rail's process tree AND cancels its queued
230
+ jobs (autonomous level).
231
+ - \`specrails_jobs(spawn, command)\` bypasses rails to enqueue an arbitrary
232
+ slash-command job (e.g. \`/specrails:implement #5 --yes\`). Use rails for
233
+ normal implement flows; spawn for advanced one-offs.
234
+ - After a 202, report the returned jobId(s)/ids VERBATIM and tell the user they
235
+ can also watch live in the app (rail header, Job Detail page). Then follow
236
+ with \`specrails_watch\` — long rails outlive the default 120 s window, so size
237
+ \`untilMs\` up (max 600000); on \`{settled:false}\` say the job is still running
238
+ and either watch again or poll \`specrails_jobs(get)\`. Never claim completion
239
+ you have not verified from a terminal event or a job read.
240
+ - While watching, stay silent — do not post per-event narration.
241
+ - On settle, report in ONE message: outcome, what the pipeline did to the
242
+ spec's status (done / reverted to todo / done with the needs-review flag —
243
+ these are pipeline-managed; do not "fix" them yourself), duration, and cost —
244
+ prefix the cost with \`~\` when the provider reports an estimate
245
+ (codex/gemini). Offer the Analytics page for detail. On failure, report the
246
+ failure faithfully and offer the diagnostic export.
247
+
248
+ ## Stance
249
+
250
+ Be concise and action-oriented. Confirm what you did with concrete references
251
+ (ids, names). Never fabricate results — report tool outputs faithfully,
252
+ including failures. Announce cost before spending; announce risk before
253
+ destroying.
254
+
255
+ ## Formatting
256
+
257
+ Make replies easy to read: separate distinct ideas into short paragraphs with a
258
+ blank line between them (avoid one dense block of text), and use bullet lists
259
+ for enumerations. Give the conversation some breathing room.
260
+
261
+ ## Adding a project
262
+
263
+ When the user has no projects yet, or asks to add one:
264
+ 1. Explain the UI path: click "Add Project" (the + in the left sidebar), enter
265
+ the repo's folder path, pick an AI provider, then run setup.
266
+ 2. Then OFFER to do it from here: ask for the repo folder path and which AI
267
+ providers to set up, then with their go-ahead call
268
+ \`specrails_setup(add_project, path, providers)\` (edit level) and a SINGLE
269
+ \`specrails_setup(install, projectId)\` (operate level) — one install
270
+ provisions ALL the chosen providers in one shot (do not install them one at
271
+ a time). Use \`specrails_setup(prerequisites)\` / \`available_providers\` first
272
+ to confirm the machine is ready.
273
+
274
+ Setup is QUICK-only (fast, offline). Do NOT offer, mention, or attempt a "full"
275
+ or "enrich" install — that flow is deprecated and not available through you.
276
+ `;
277
+ exports.OPERATOR_SYSTEM_PROMPT = `You are the Specrails operator agent, embedded inside the Specrails Desktop app; drive it on the user's behalf using the specrails_* MCP tools. Your full operator manual is the CLAUDE.md auto-loaded from your working directory — follow it. Non-negotiables: target a project with specrails_select_project or the projectId argument, and ask rather than guess when none is pinned; follow HTTP-202 actions with specrails_watch (projectId required) and never claim success from the acceptance alone — on timeout, poll the domain read (e.g. specrails_jobs get); respect the cumulative permission ladder observe / edit / operate / autonomous — if a tool is refused, name the level the user must Shift+Tab to, never work around it; when you have refined a spec with the user, persist it with specrails_specs commit_draft (no conversationId) — never route it through create/generate, which regenerate the content with AI; report tool outputs faithfully, including failures. Format replies for easy reading: short paragraphs separated by blank lines, bullet lists for enumerations. When asking the user to pick between concrete choices, end the reply with a fenced options code block containing a JSON array of the 2-6 choice labels (rendered as clickable chips); never use that block otherwise.`;
@@ -9,6 +9,27 @@ exports.addAgentMessage = addAgentMessage;
9
9
  exports.listAgentMessages = listAgentMessages;
10
10
  const crypto_1 = require("crypto");
11
11
  const agent_tier_1 = require("./agent-tier");
12
+ function mapMessage(row) {
13
+ let ids = [];
14
+ if (row.attachment_ids) {
15
+ try {
16
+ const parsed = JSON.parse(row.attachment_ids);
17
+ if (Array.isArray(parsed))
18
+ ids = parsed.filter((x) => typeof x === 'string');
19
+ }
20
+ catch {
21
+ /* ignore malformed */
22
+ }
23
+ }
24
+ return {
25
+ id: row.id,
26
+ conversation_id: row.conversation_id,
27
+ role: row.role,
28
+ content: row.content,
29
+ attachment_ids: ids,
30
+ created_at: row.created_at,
31
+ };
32
+ }
12
33
  function mapConversation(row) {
13
34
  if (!row)
14
35
  return undefined;
@@ -16,8 +37,8 @@ function mapConversation(row) {
16
37
  }
17
38
  function createAgentConversation(db, input = {}) {
18
39
  const id = (0, crypto_1.randomUUID)();
19
- db.prepare(`INSERT INTO agent_conversations (id, provider, model, pinned_project_id, tier_level)
20
- VALUES (?, ?, ?, ?, ?)`).run(id, input.provider ?? 'claude', input.model ?? null, input.pinnedProjectId ?? null, input.tierLevel ?? 0);
40
+ db.prepare(`INSERT INTO agent_conversations (id, provider, model, pinned_project_id, tier_level, reasoning_effort)
41
+ VALUES (?, ?, ?, ?, ?, ?)`).run(id, input.provider ?? 'claude', input.model ?? null, input.pinnedProjectId ?? null, input.tierLevel ?? 0, input.reasoningEffort ?? null);
21
42
  return getAgentConversation(db, id);
22
43
  }
23
44
  function getAgentConversation(db, id) {
@@ -47,13 +68,14 @@ function deleteAgentConversation(db, id) {
47
68
  }
48
69
  function addAgentMessage(db, input) {
49
70
  const id = (0, crypto_1.randomUUID)();
50
- db.prepare('INSERT INTO agent_messages (id, conversation_id, role, content) VALUES (?, ?, ?, ?)').run(id, input.conversationId, input.role, input.content);
71
+ const attachmentIds = input.attachmentIds && input.attachmentIds.length ? JSON.stringify(input.attachmentIds) : null;
72
+ db.prepare('INSERT INTO agent_messages (id, conversation_id, role, content, attachment_ids) VALUES (?, ?, ?, ?, ?)').run(id, input.conversationId, input.role, input.content, attachmentIds);
51
73
  // Touch the parent so the list stays ordered by latest activity.
52
74
  db.prepare("UPDATE agent_conversations SET updated_at = datetime('now') WHERE id = ?").run(input.conversationId);
53
- return db.prepare('SELECT * FROM agent_messages WHERE id = ?').get(id);
75
+ return mapMessage(db.prepare('SELECT * FROM agent_messages WHERE id = ?').get(id));
54
76
  }
55
77
  function listAgentMessages(db, conversationId) {
56
78
  return db
57
79
  .prepare('SELECT * FROM agent_messages WHERE conversation_id = ? ORDER BY created_at ASC, rowid ASC')
58
- .all(conversationId);
80
+ .all(conversationId).map(mapMessage);
59
81
  }
@@ -302,6 +302,144 @@ class AttachmentManager {
302
302
  }
303
303
  return textBlocks;
304
304
  }
305
+ // ── Agent-scoped attachments ──────────────────────────────────────────────
306
+ // App-global agent conversations have no project slug/ticket, so their
307
+ // attachments live under a distinct, conversation-keyed root
308
+ // `~/.specrails/agent/<conversationId>/attachments/` (never the project
309
+ // attachments root — that risks slug collisions and doesn't fit Home convos).
310
+ static AGENT_CONV_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
311
+ agentDir(conversationId) {
312
+ const key = String(conversationId);
313
+ if (key === '' || key === '.' || key === '..' || key !== path_1.default.basename(key) ||
314
+ key.includes('/') || key.includes('\\') || !AttachmentManager.AGENT_CONV_ID_RE.test(key)) {
315
+ throw new Error(`Invalid agent conversation id: ${JSON.stringify(key)}`);
316
+ }
317
+ return path_1.default.join(this.homeDir, '.specrails', 'agent', key, 'attachments');
318
+ }
319
+ agentSidecarPath(conversationId, attachmentId) {
320
+ this.assertValidAttachmentId(attachmentId);
321
+ return path_1.default.join(this.agentDir(conversationId), `${attachmentId}.meta.json`);
322
+ }
323
+ readAgentMeta(conversationId, attachmentId) {
324
+ const p = this.agentSidecarPath(conversationId, attachmentId);
325
+ if (!fs_1.default.existsSync(p))
326
+ return null;
327
+ try {
328
+ return JSON.parse(fs_1.default.readFileSync(p, 'utf-8'));
329
+ }
330
+ catch {
331
+ return null;
332
+ }
333
+ }
334
+ async uploadAgent(opts) {
335
+ const normalizedMimeType = normalizeUploadedMimeType(opts.file.mimetype, opts.file.originalname);
336
+ if (!exports.SUPPORTED_MIME_TYPES.has(normalizedMimeType)) {
337
+ const err = new Error(`Unsupported file type: ${opts.file.mimetype}`);
338
+ err.status = 400;
339
+ throw err;
340
+ }
341
+ const id = (0, ids_1.newId)();
342
+ const storedName = `${id}-${sanitizeFilename(opts.file.originalname)}`;
343
+ const attachment = {
344
+ id,
345
+ filename: opts.file.originalname,
346
+ storedName,
347
+ mimeType: normalizedMimeType,
348
+ size: opts.file.size,
349
+ addedAt: new Date().toISOString(),
350
+ };
351
+ const dir = this.agentDir(opts.conversationId);
352
+ fs_1.default.mkdirSync(dir, { recursive: true });
353
+ fs_1.default.writeFileSync(path_1.default.join(dir, storedName), opts.file.buffer);
354
+ fs_1.default.writeFileSync(this.agentSidecarPath(opts.conversationId, id), JSON.stringify(attachment, null, 2), 'utf-8');
355
+ return attachment;
356
+ }
357
+ listAgent(conversationId) {
358
+ let dir;
359
+ try {
360
+ dir = this.agentDir(conversationId);
361
+ }
362
+ catch {
363
+ return [];
364
+ }
365
+ if (!fs_1.default.existsSync(dir))
366
+ return [];
367
+ return fs_1.default
368
+ .readdirSync(dir)
369
+ .filter((f) => f.endsWith('.meta.json'))
370
+ .map((f) => {
371
+ try {
372
+ return JSON.parse(fs_1.default.readFileSync(path_1.default.join(dir, f), 'utf-8'));
373
+ }
374
+ catch {
375
+ return null;
376
+ }
377
+ })
378
+ .filter((m) => m !== null)
379
+ .sort((a, b) => (a.addedAt < b.addedAt ? 1 : -1));
380
+ }
381
+ getAgentMeta(conversationId, attachmentId) {
382
+ return this.readAgentMeta(conversationId, attachmentId);
383
+ }
384
+ getAgentFilePath(conversationId, attachmentId) {
385
+ const meta = this.readAgentMeta(conversationId, attachmentId);
386
+ if (!meta)
387
+ return null;
388
+ const abs = path_1.default.join(this.agentDir(conversationId), meta.storedName);
389
+ return fs_1.default.existsSync(abs) ? abs : null;
390
+ }
391
+ async deleteAgent(conversationId, attachmentId) {
392
+ const meta = this.readAgentMeta(conversationId, attachmentId);
393
+ if (!meta)
394
+ return false;
395
+ const dir = this.agentDir(conversationId);
396
+ const bin = path_1.default.join(dir, meta.storedName);
397
+ if (fs_1.default.existsSync(bin))
398
+ fs_1.default.unlinkSync(bin);
399
+ const side = this.agentSidecarPath(conversationId, attachmentId);
400
+ if (fs_1.default.existsSync(side))
401
+ fs_1.default.unlinkSync(side);
402
+ return true;
403
+ }
404
+ /** Remove the entire per-conversation agent directory (attachments + siblings). */
405
+ async deleteAllAgent(conversationId) {
406
+ // Validate the id (throws on traversal) then remove the parent conversation dir.
407
+ this.agentDir(conversationId);
408
+ const dir = path_1.default.join(this.homeDir, '.specrails', 'agent', String(conversationId));
409
+ if (fs_1.default.existsSync(dir))
410
+ fs_1.default.rmSync(dir, { recursive: true, force: true });
411
+ }
412
+ /**
413
+ * Agent variant of getClaudeArgs, keyed by conversation id. Returns extracted
414
+ * text blocks (all providers) AND absolute image paths (codex `--image`). The
415
+ * image `@<abs-path>` stays in textBlocks so claude resolves it and gemini gets
416
+ * a best-effort shot; `imagePaths` is additive and only codex consumes it.
417
+ */
418
+ async getClaudeArgsAgent(conversationId, attachmentIds) {
419
+ const textBlocks = [];
420
+ const imagePaths = [];
421
+ for (const id of attachmentIds) {
422
+ const meta = this.readAgentMeta(conversationId, id);
423
+ if (!meta)
424
+ continue;
425
+ const abs = path_1.default.join(this.agentDir(conversationId), meta.storedName);
426
+ if (!fs_1.default.existsSync(abs))
427
+ continue;
428
+ if (meta.mimeType.startsWith(IMAGE_MIME_PREFIX)) {
429
+ imagePaths.push(abs);
430
+ textBlocks.push(wrapUserAttachment(meta, `@${abs}`));
431
+ continue;
432
+ }
433
+ try {
434
+ const text = await extractText(abs, meta.mimeType);
435
+ textBlocks.push(wrapUserAttachment(meta, text));
436
+ }
437
+ catch {
438
+ textBlocks.push(wrapUserAttachment(meta, '[extraction failed]'));
439
+ }
440
+ }
441
+ return { textBlocks, imagePaths };
442
+ }
305
443
  }
306
444
  exports.AttachmentManager = AttachmentManager;
307
445
  function wrapUserAttachment(meta, content) {
@@ -378,6 +378,18 @@ function applyDesktopMigrations(db) {
378
378
  CREATE INDEX IF NOT EXISTS idx_agent_messages_conv ON agent_messages(conversation_id, created_at);
379
379
  `);
380
380
  },
381
+ // 18: persist the per-turn attachment id list on user messages so historical
382
+ // agent turns re-render pills/thumbnails after refresh (design D20). Nullable
383
+ // JSON array of attachment ids; NULL/absent = text-only turn (all old rows).
384
+ () => {
385
+ db.exec(`ALTER TABLE agent_messages ADD COLUMN attachment_ids TEXT;`);
386
+ },
387
+ // 19: per-conversation reasoning effort for agent spawns. NULL = the app
388
+ // default ("medium"); validated against the provider's effort catalog at the
389
+ // router (claude: low…xhigh, codex: minimal…high, gemini: none).
390
+ () => {
391
+ db.exec(`ALTER TABLE agent_conversations ADD COLUMN reasoning_effort TEXT;`);
392
+ },
381
393
  ];
382
394
  for (let i = 0; i < migrations.length; i++) {
383
395
  const version = i + 1;
@@ -444,6 +456,9 @@ function addProject(db, project) {
444
456
  }
445
457
  function removeProject(db, id) {
446
458
  db.prepare('DELETE FROM projects WHERE id = ?').run(id);
459
+ // No FK on agent_conversations.pinned_project_id — unpin so orphaned agent
460
+ // conversations fold into Home instead of dangling on a dead project id.
461
+ db.prepare('UPDATE agent_conversations SET pinned_project_id = NULL WHERE pinned_project_id = ?').run(id);
447
462
  }
448
463
  function touchProject(db, id) {
449
464
  db.prepare("UPDATE projects SET last_seen_at = datetime('now') WHERE id = ?").run(id);
@@ -31,12 +31,22 @@ exports.FACTORY_LOOPS = [
31
31
  },
32
32
  {
33
33
  id: 'factory:ultracode',
34
- name: 'Ultracode',
35
- description: 'Autonomous per-ticket implementation (no pipeline), then verify + refine until green. Claude only.',
34
+ // Renamed from "Ultracode": the mode hands the spec straight to the model
35
+ // with full freedom — no pipeline, it works like a regular coding agent.
36
+ // The id/mode strings stay 'ultracode' (wire + rail back-compat).
37
+ name: 'Freestyle',
38
+ description: 'Hands the spec straight to the model with full freedom — no pipeline, it works like a regular coding agent, then verify + refine until green. Claude only.',
36
39
  mode: 'ultracode',
37
40
  claudeOnly: true,
38
41
  graph: (0, loop_templates_1.fixLoopGraph)(['{{cmd:ultracode}}'], GREEN_GOAL, FACTORY_MAX_ITERATIONS, FACTORY_LOOP_TIMEOUT_MIN, FACTORY_AI_STEP_TIMEOUT_MIN),
39
42
  },
43
+ {
44
+ id: 'factory:openspec',
45
+ name: 'OpenSpec Lifecycle',
46
+ description: 'Ticket-to-archive OpenSpec lifecycle: generate artifacts (opsx:ff) → implement (opsx:apply) → verify (opsx:verify); on FAIL loop back and amend the same change, on PASS archive it unattended.',
47
+ mode: 'loop',
48
+ graph: (0, loop_templates_1.opsxLifecycleGraph)(),
49
+ },
40
50
  ];
41
51
  const FACTORY_BY_ID = new Map(exports.FACTORY_LOOPS.map((f) => [f.id, f]));
42
52
  function getFactoryLoop(id) {