specrails-desktop 2.16.0 → 2.18.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 (424) hide show
  1. package/client/dist/assets/{ActivityFeedPage-C_clKk8d.js → ActivityFeedPage-mGnv5SOe.js} +1 -1
  2. package/client/dist/assets/AgentsPage-BH1isg5j.js +86 -0
  3. package/client/dist/assets/AnalyticsPage-ByyshYRI.js +1 -0
  4. package/client/dist/assets/{BarChart-Dq1h8eYR.js → BarChart-BqHUOnl9.js} +3 -3
  5. package/client/dist/assets/CodePage-CU7T_HYs.js +2 -0
  6. package/client/dist/assets/{DesktopAnalyticsPage-CYhXhJoQ.js → DesktopAnalyticsPage-CR-m97Ui.js} +1 -1
  7. package/client/dist/assets/DocsDialog-CEmZp_8V.js +11 -0
  8. package/client/dist/assets/DocsPage-DYbAQ1AT.js +11 -0
  9. package/client/dist/assets/{ExportDropdown-DdB2ncYh.js → ExportDropdown-C-o1Q4ef.js} +1 -1
  10. package/client/dist/assets/IntegrationsPage-C6fKdwVH.js +3 -0
  11. package/client/dist/assets/JobDetailPage-CKfIfBgE.js +16 -0
  12. package/client/dist/assets/JobsPage-nBng0riZ.js +1 -0
  13. package/client/dist/assets/LoopBuilderPage-Co_TYqYk.js +7 -0
  14. package/client/dist/assets/LoopsPage-a2hd37Ya.js +1 -0
  15. package/client/dist/assets/{activity-Ca2XoBi-.js → activity-D8vQJrpW.js} +1 -1
  16. package/client/dist/assets/{addon-image-biWX2UUm.js → addon-image-Ba-TY3wr.js} +1 -1
  17. package/client/dist/assets/{addon-ligatures-D4EiDb5r.js → addon-ligatures-T4ARLiuu.js} +1 -1
  18. package/client/dist/assets/{addon-webgl-CDCIZQ03.js → addon-webgl-Cd73n8eh.js} +1 -1
  19. package/client/dist/assets/{addspec-DE_VfIyP.js → addspec-BloGn_ey.js} +1 -1
  20. package/client/dist/assets/agent-9WdSxPU5.js +1 -0
  21. package/client/dist/assets/agent-ASIyVcg0.js +1 -0
  22. package/client/dist/assets/agent-Bm2tPrdr.js +1 -0
  23. package/client/dist/assets/agent-C4bO1l_v.js +1 -0
  24. package/client/dist/assets/agent-CgKsh88Z2.js +1 -0
  25. package/client/dist/assets/agent-DMUrz9ZS2.js +1 -0
  26. package/client/dist/assets/agent-Dwkz5mPS.js +1 -0
  27. package/client/dist/assets/agent-pO8x4jbR.js +1 -0
  28. package/client/dist/assets/{agents-DcoUUFZl.js → agents-52t8NVpS.js} +1 -1
  29. package/client/dist/assets/{agents-DCX9D3-Q.js → agents-BAxAwHy-.js} +1 -1
  30. package/client/dist/assets/{agents-Jc-CjBDB.js → agents-BUYBb825.js} +1 -1
  31. package/client/dist/assets/{agents-CIhRSOna.js → agents-BjT_xLjv.js} +1 -1
  32. package/client/dist/assets/{agents-BYjUOrLD.js → agents-C07al8rI.js} +1 -1
  33. package/client/dist/assets/{agents-1lhqEcXH.js → agents-DfGvYtpq2.js} +1 -1
  34. package/client/dist/assets/{agents-CQlu1nOm.js → agents-Dli56gr82.js} +1 -1
  35. package/client/dist/assets/{agents-DVYpVGur.js → agents-Eqw_AQ6H.js} +1 -1
  36. package/client/dist/assets/{agentstudio-DCTpIqOx.js → agentstudio-CZm2rOzt.js} +1 -1
  37. package/client/dist/assets/{aiedit-Dirqf3Bm.js → aiedit-DYtnZU9H.js} +1 -1
  38. package/client/dist/assets/{analytics-BE49LbUk.js → analytics-B4FJ_pry.js} +1 -1
  39. package/client/dist/assets/{attachments-C2JPppoP.js → attachments-Ci6_42Kh.js} +1 -1
  40. package/client/dist/assets/{browser-Dpo_ug4c.js → browser-ZB1afzjZ.js} +1 -1
  41. package/client/dist/assets/{chat-mq1x9cxZ.js → chat-VMflhzxn.js} +1 -1
  42. package/client/dist/assets/chunk-BNv3lrIs.js +1 -0
  43. package/client/dist/assets/{code-DtIatVES.js → code-wtcs0ivb.js} +1 -1
  44. package/client/dist/assets/commands-Bc8y9eNo2.js +1 -0
  45. package/client/dist/assets/commands-Bl3-KVfj.js +1 -0
  46. package/client/dist/assets/commands-C5WQ9blx2.js +1 -0
  47. package/client/dist/assets/commands-CM99Upsz2.js +1 -0
  48. package/client/dist/assets/commands-Cc2WpuXa.js +1 -0
  49. package/client/dist/assets/commands-CckaBWdV.js +1 -0
  50. package/client/dist/assets/commands-DASXJD-l.js +1 -0
  51. package/client/dist/assets/commands-k9wbNYoi.js +1 -0
  52. package/client/dist/assets/{common-kftoE0Q-.js → common-BPQQkgJZ.js} +1 -1
  53. package/client/dist/assets/{cssMode-DSHXamUH.js → cssMode-DsArsSCT.js} +1 -1
  54. package/client/dist/assets/{dashboard-BQ3Oa8CE.js → dashboard-Cyzp4ox9.js} +1 -1
  55. package/client/dist/assets/{dist-js-Ele_sHO7.js → dist-js-BHhtSerX.js} +1 -1
  56. package/client/dist/assets/{dist-js-D27I-bfi.js → dist-js-CUegfF6k.js} +1 -1
  57. package/client/dist/assets/{editor.api2-Cwla1nvV.js → editor.api2-T7u8kQWG.js} +1 -1
  58. package/client/dist/assets/{editor.main-Cd8qBRAT.js → editor.main-G3Sl9C67.js} +2 -2
  59. package/client/dist/assets/{explore-CBYU76JD.js → explore-BKVV5JSu.js} +1 -1
  60. package/client/dist/assets/{freemarker2-CkEKTBm2.js → freemarker2-pBzQNgFi.js} +1 -1
  61. package/client/dist/assets/{handlebars-BRGx0JpL.js → handlebars-CtBTCnBI.js} +1 -1
  62. package/client/dist/assets/{html-BfRIaGgN.js → html-Dx3DYBzY.js} +1 -1
  63. package/client/dist/assets/{htmlMode-BTpSnsDE.js → htmlMode-In7frFOo.js} +1 -1
  64. package/client/dist/assets/index-B0FxQALR.css +2 -0
  65. package/client/dist/assets/index-B7vB20Jw.js +152 -0
  66. package/client/dist/assets/{integrations-jJGaKwff.js → integrations-CuWnMR5L.js} +1 -1
  67. package/client/dist/assets/{javascript-DMmE2kKN.js → javascript-BKcn-YkN.js} +1 -1
  68. package/client/dist/assets/{jira-BwACz875.js → jira-DXMoAKWD.js} +1 -1
  69. package/client/dist/assets/{jobs-DRInW0AE.js → jobs---dwa4Nf.js} +1 -1
  70. package/client/dist/assets/{jsonMode-hYuaUleY.js → jsonMode-jNREoQ3C.js} +1 -1
  71. package/client/dist/assets/{lib-qdRfWwE1.js → lib-PQoHlR5u.js} +2 -2
  72. package/client/dist/assets/{liquid-C-VbuTr7.js → liquid-CtRkGqBu.js} +1 -1
  73. package/client/dist/assets/{loops-DfGadne0.js → loops-D8Iu6Jss.js} +1 -1
  74. package/client/dist/assets/{lspLanguageFeatures-BALx-vjn.js → lspLanguageFeatures-Cl3gvD_W.js} +1 -1
  75. package/client/dist/assets/mcp-B4irfLJ2.js +1 -0
  76. package/client/dist/assets/mcp-B6nwJJmR.js +1 -0
  77. package/client/dist/assets/mcp-BOoEGTSQ.js +1 -0
  78. package/client/dist/assets/mcp-BP7PpbDr2.js +1 -0
  79. package/client/dist/assets/mcp-CIH0pH1K.js +1 -0
  80. package/client/dist/assets/mcp-CNgFiTEh.js +1 -0
  81. package/client/dist/assets/mcp-D3E4_Mmk2.js +1 -0
  82. package/client/dist/assets/mcp-mupPuPDO2.js +1 -0
  83. package/client/dist/assets/{mdx-Cs8MNCzn.js → mdx-B_nJldHz.js} +1 -1
  84. package/client/dist/assets/{monaco.contribution-CIvCAJs4.js → monaco.contribution-PUeaZk8T.js} +2 -2
  85. package/client/dist/assets/{nav-CCz4krPP.js → nav-DE3yWQw6.js} +1 -1
  86. package/client/dist/assets/{python-CGShLxuI.js → python-DS1Ce-A6.js} +1 -1
  87. package/client/dist/assets/{razor-CvOBQGd5.js → razor-L41Qg9OK.js} +1 -1
  88. package/client/dist/assets/settings-BKmORxlB2.js +1 -0
  89. package/client/dist/assets/settings-BVv2JgQ8.js +1 -0
  90. package/client/dist/assets/settings-Bghm3pAV.js +1 -0
  91. package/client/dist/assets/settings-BuC_aplX.js +1 -0
  92. package/client/dist/assets/settings-Bw_Qk8E32.js +1 -0
  93. package/client/dist/assets/settings-CAKgJv7p.js +1 -0
  94. package/client/dist/assets/settings-CEUgk1Ck.js +1 -0
  95. package/client/dist/assets/settings-C_PDE20s2.js +1 -0
  96. package/client/dist/assets/setup-4us-Bz3H.js +1 -0
  97. package/client/dist/assets/setup-BYoDYoPY2.js +1 -0
  98. package/client/dist/assets/setup-Bf9eLKxU.js +1 -0
  99. package/client/dist/assets/setup-C5UbM0RP.js +1 -0
  100. package/client/dist/assets/setup-CqGrWb6G.js +1 -0
  101. package/client/dist/assets/setup-JFkWWZnR.js +1 -0
  102. package/client/dist/assets/setup-faMApo0U2.js +1 -0
  103. package/client/dist/assets/setup-tloaTobG2.js +1 -0
  104. package/client/dist/assets/{specs-C_8j4ELZ.js → specs-BYeAbIEy.js} +1 -1
  105. package/client/dist/assets/{terminal-Cj4HzP3p.js → terminal-DFPNRLKp.js} +1 -1
  106. package/client/dist/assets/{tickets-DBQXMYYA.js → tickets-CkfbISuK.js} +1 -1
  107. package/client/dist/assets/{tsMode-04uOpiiP.js → tsMode-BC1g186U.js} +1 -1
  108. package/client/dist/assets/{typescript-CX0CwyIZ.js → typescript-BGlRGvJW.js} +1 -1
  109. package/client/dist/assets/upload-PnJDPHZH.js +1 -0
  110. package/client/dist/assets/{value-BRVOAvhY.js → value-BTDefcOV.js} +1 -1
  111. package/client/dist/assets/{workers-yr2u4c3C.js → workers-CXcXtO3b.js} +1 -1
  112. package/client/dist/assets/{xml-C0OFlt5X.js → xml-JdZZaIhJ.js} +1 -1
  113. package/client/dist/assets/{yaml-DgabaPs5.js → yaml-Cm82BVBt.js} +1 -1
  114. package/client/dist/index.html +30 -28
  115. package/docs/README.md +2 -0
  116. package/docs/guide/de/integrations/5-mcp-server.md +74 -0
  117. package/docs/guide/de/integrations/6-agent-chat.md +64 -0
  118. package/docs/guide/en/integrations/5-mcp-server.md +74 -0
  119. package/docs/guide/en/integrations/6-agent-chat.md +64 -0
  120. package/docs/guide/es/integrations/5-mcp-server.md +74 -0
  121. package/docs/guide/es/integrations/6-agent-chat.md +64 -0
  122. package/docs/guide/fr/integrations/5-mcp-server.md +74 -0
  123. package/docs/guide/fr/integrations/6-agent-chat.md +64 -0
  124. package/docs/guide/it/integrations/5-mcp-server.md +74 -0
  125. package/docs/guide/it/integrations/6-agent-chat.md +64 -0
  126. package/docs/guide/ja/integrations/5-mcp-server.md +74 -0
  127. package/docs/guide/ja/integrations/6-agent-chat.md +64 -0
  128. package/docs/guide/pt/integrations/5-mcp-server.md +74 -0
  129. package/docs/guide/pt/integrations/6-agent-chat.md +64 -0
  130. package/docs/guide/zh/integrations/5-mcp-server.md +74 -0
  131. package/docs/guide/zh/integrations/6-agent-chat.md +64 -0
  132. package/docs/mcp.md +249 -0
  133. package/package.json +8 -5
  134. package/server/dist/agent-chat-manager.js +224 -0
  135. package/server/dist/agent-chat-router.js +148 -0
  136. package/server/dist/agent-cwd-manager.js +94 -0
  137. package/server/dist/agent-mcp-config.js +208 -0
  138. package/server/dist/agent-store.js +59 -0
  139. package/server/dist/agent-tier.js +86 -0
  140. package/server/dist/desktop-db.js +27 -0
  141. package/server/dist/index.js +38 -0
  142. package/server/dist/mcp/guide.js +82 -0
  143. package/server/dist/mcp/index.js +21 -0
  144. package/server/dist/mcp/mcp-admin-router.js +71 -0
  145. package/server/dist/mcp/mcp-server.js +143 -0
  146. package/server/dist/mcp/mcp-tiers.js +48 -0
  147. package/server/dist/mcp/mcp-token.js +119 -0
  148. package/server/dist/mcp/resources.js +24 -0
  149. package/server/dist/mcp/tools/agents.js +319 -0
  150. package/server/dist/mcp/tools/analytics.js +168 -0
  151. package/server/dist/mcp/tools/app-settings.js +81 -0
  152. package/server/dist/mcp/tools/catalog.js +45 -0
  153. package/server/dist/mcp/tools/chat.js +147 -0
  154. package/server/dist/mcp/tools/code.js +145 -0
  155. package/server/dist/mcp/tools/jira.js +222 -0
  156. package/server/dist/mcp/tools/jobs.js +258 -0
  157. package/server/dist/mcp/tools/loops.js +229 -0
  158. package/server/dist/mcp/tools/meta.js +96 -0
  159. package/server/dist/mcp/tools/plugins.js +83 -0
  160. package/server/dist/mcp/tools/projects.js +62 -0
  161. package/server/dist/mcp/tools/rails.js +181 -0
  162. package/server/dist/mcp/tools/setup.js +167 -0
  163. package/server/dist/mcp/tools/specs.js +327 -0
  164. package/server/dist/mcp/tools/types.js +156 -0
  165. package/server/dist/mcp/tools/watch.js +93 -0
  166. package/server/dist/mobile/mobile-event-bus.js +2 -0
  167. package/server/dist/project-router-setup.js +15 -1
  168. package/server/dist/project-router-tickets.js +2 -2
  169. package/server/dist/providers/codex-adapter.js +19 -3
  170. package/server/dist/rails-router.js +5 -0
  171. package/server/dist/setup-manager.js +28 -0
  172. package/server/dist/spawn-lifecycle.js +21 -13
  173. package/server/dist/workspace-manager.js +11 -0
  174. package/client/dist/assets/AgentsPage-jcPUtPhP.js +0 -86
  175. package/client/dist/assets/AnalyticsPage-DZkVU3yd.js +0 -1
  176. package/client/dist/assets/CodePage-BcbZT88K.js +0 -2
  177. package/client/dist/assets/DocsDialog-CS3Syf61.js +0 -11
  178. package/client/dist/assets/DocsPage-l3ZcTO2E.js +0 -11
  179. package/client/dist/assets/IntegrationsPage-CJ_Om1zu.js +0 -3
  180. package/client/dist/assets/JobDetailPage-D5Cxw0md.js +0 -16
  181. package/client/dist/assets/JobsPage-3v_iX83r.js +0 -1
  182. package/client/dist/assets/LoopBuilderPage-4s_adZy5.js +0 -7
  183. package/client/dist/assets/LoopsPage-DA94-o0j.js +0 -1
  184. package/client/dist/assets/chunk-CilyBKbf.js +0 -1
  185. package/client/dist/assets/commands-B9XEyMj-.js +0 -1
  186. package/client/dist/assets/commands-BI1Ta-E7.js +0 -1
  187. package/client/dist/assets/commands-BdI0CtOL.js +0 -1
  188. package/client/dist/assets/commands-C2ewlyXo.js +0 -1
  189. package/client/dist/assets/commands-CwypztRT.js +0 -1
  190. package/client/dist/assets/commands-DSX3yJyr.js +0 -1
  191. package/client/dist/assets/commands-Ic1DJDxm.js +0 -1
  192. package/client/dist/assets/commands-yNn4IA4C.js +0 -1
  193. package/client/dist/assets/index-BRMyOS1B.css +0 -2
  194. package/client/dist/assets/index-meTWPBzY.js +0 -144
  195. package/client/dist/assets/settings-0m2iuTzd.js +0 -1
  196. package/client/dist/assets/settings-BA1V6KdK.js +0 -1
  197. package/client/dist/assets/settings-BN7OusER.js +0 -1
  198. package/client/dist/assets/settings-Bi5FFkIw.js +0 -1
  199. package/client/dist/assets/settings-CRJxyTNN.js +0 -1
  200. package/client/dist/assets/settings-DyBxunCh.js +0 -1
  201. package/client/dist/assets/settings-fk-WlnUt.js +0 -1
  202. package/client/dist/assets/settings-iQe5Dim-.js +0 -1
  203. package/client/dist/assets/setup-BOmQ4vh2.js +0 -1
  204. package/client/dist/assets/setup-BwO2-kuK.js +0 -1
  205. package/client/dist/assets/setup-CUTNWz-0.js +0 -1
  206. package/client/dist/assets/setup-Cf3hjChU.js +0 -1
  207. package/client/dist/assets/setup-CsuXrbJ2.js +0 -1
  208. package/client/dist/assets/setup-Df4cJOqu.js +0 -1
  209. package/client/dist/assets/setup-Do0fWx6W.js +0 -1
  210. package/client/dist/assets/setup-GlkDhBlJ.js +0 -1
  211. package/client/dist/assets/upload-DPG87J4t.js +0 -1
  212. /package/client/dist/assets/{abap-CK68cr9-.js → abap-CpHUwCVK.js} +0 -0
  213. /package/client/dist/assets/{activity-Di2f50_Z.js → activity-B82z3Pna.js} +0 -0
  214. /package/client/dist/assets/{activity-B2MvEH54.js → activity-BId0pwuS2.js} +0 -0
  215. /package/client/dist/assets/{activity-D4dhNEwO.js → activity-BVpZrs0J.js} +0 -0
  216. /package/client/dist/assets/{activity-DHjfmAyT.js → activity-BySXFT2J2.js} +0 -0
  217. /package/client/dist/assets/{activity-usnNa7FX.js → activity-DIWnV0Pl.js} +0 -0
  218. /package/client/dist/assets/{activity-C7VdmeGb.js → activity-Uj576ckT.js} +0 -0
  219. /package/client/dist/assets/{activity-BbNkUmW4.js → activity-w1qMFwxh.js} +0 -0
  220. /package/client/dist/assets/{addspec-CO1xv6BL.js → addspec-B9dY_F5T.js} +0 -0
  221. /package/client/dist/assets/{addspec-CNyAUGz_.js → addspec-B9nhMikb.js} +0 -0
  222. /package/client/dist/assets/{addspec-IozoiiGs.js → addspec-BtNaJHu2.js} +0 -0
  223. /package/client/dist/assets/{addspec-BxMn39wn.js → addspec-D43TlMVp2.js} +0 -0
  224. /package/client/dist/assets/{addspec-1HEtmLv1.js → addspec-DfgIZ5lO.js} +0 -0
  225. /package/client/dist/assets/{addspec-DfuR6EAl.js → addspec-W0r16BOC2.js} +0 -0
  226. /package/client/dist/assets/{addspec-DAveBiCE.js → addspec-tbxr3sHa.js} +0 -0
  227. /package/client/dist/assets/{agentstudio-DCyDW8sy.js → agentstudio-0o3XKrcy.js} +0 -0
  228. /package/client/dist/assets/{agentstudio-9NbsoGXk.js → agentstudio-Bu8m5jDw.js} +0 -0
  229. /package/client/dist/assets/{agentstudio-B1y0JWY-.js → agentstudio-C7xxqVWn.js} +0 -0
  230. /package/client/dist/assets/{agentstudio-1E-bag77.js → agentstudio-D-UoNAIA.js} +0 -0
  231. /package/client/dist/assets/{agentstudio-B-jQgYV-.js → agentstudio-OJjjz6Uf2.js} +0 -0
  232. /package/client/dist/assets/{agentstudio-Q0Sq_jTg.js → agentstudio-ObTpVbBP.js} +0 -0
  233. /package/client/dist/assets/{agentstudio-Bwa72b1S.js → agentstudio-PzFB3vfh2.js} +0 -0
  234. /package/client/dist/assets/{aiedit-DUpe7NxI.js → aiedit-BIQqv2XM2.js} +0 -0
  235. /package/client/dist/assets/{aiedit-kAU7KADg.js → aiedit-BaLZalLa.js} +0 -0
  236. /package/client/dist/assets/{aiedit-CvSspQmE.js → aiedit-BjlUzasF.js} +0 -0
  237. /package/client/dist/assets/{aiedit-DSLtsYIu.js → aiedit-BmDufyGU.js} +0 -0
  238. /package/client/dist/assets/{aiedit-qTGI_PGs.js → aiedit-DAM_WRAl2.js} +0 -0
  239. /package/client/dist/assets/{aiedit-CfBNanHE.js → aiedit-DRrNiaB4.js} +0 -0
  240. /package/client/dist/assets/{aiedit-CGxeml8D.js → aiedit-sP_iao2j.js} +0 -0
  241. /package/client/dist/assets/{analytics-CgEkAUiP.js → analytics-BDqqCzN9.js} +0 -0
  242. /package/client/dist/assets/{analytics-DEsEAJZL.js → analytics-B_rxNC9X.js} +0 -0
  243. /package/client/dist/assets/{analytics-D1ElChhs.js → analytics-C4z_NgJZ.js} +0 -0
  244. /package/client/dist/assets/{analytics-DDqve9Ma.js → analytics-DL2vJCbq.js} +0 -0
  245. /package/client/dist/assets/{analytics-CQqu1yE5.js → analytics-Ds_PNxtO2.js} +0 -0
  246. /package/client/dist/assets/{analytics-BDlELxc7.js → analytics-MVJRjcY52.js} +0 -0
  247. /package/client/dist/assets/{analytics-DBGO8B6-.js → analytics-e1mkNTgy2.js} +0 -0
  248. /package/client/dist/assets/{apex-BHHyAVNb.js → apex-DlD7oJX6.js} +0 -0
  249. /package/client/dist/assets/{atom-one-dark-DrWoEEbZ.js → atom-one-dark-BrRN8wBy.js} +0 -0
  250. /package/client/dist/assets/{attachments-BNgH6Tcu.js → attachments-8QCKHCEF2.js} +0 -0
  251. /package/client/dist/assets/{attachments-BLqqPGyy.js → attachments-BP0Ac1yt.js} +0 -0
  252. /package/client/dist/assets/{attachments-UJtEq892.js → attachments-CJaO1vCH.js} +0 -0
  253. /package/client/dist/assets/{attachments-D5fVsMgb.js → attachments-CPBVeHX72.js} +0 -0
  254. /package/client/dist/assets/{attachments-3CuBBRFu.js → attachments-CV2uaTGE.js} +0 -0
  255. /package/client/dist/assets/{attachments-CppM7de8.js → attachments-CaOjdN332.js} +0 -0
  256. /package/client/dist/assets/{attachments-pW3zm9nu.js → attachments-Db7JfA8a.js} +0 -0
  257. /package/client/dist/assets/{azcli-C56lfIEP.js → azcli-CmXFAbc-.js} +0 -0
  258. /package/client/dist/assets/{bat-BLamSaf-.js → bat-DdNJq4hH.js} +0 -0
  259. /package/client/dist/assets/{bicep-lrOcEItS.js → bicep-Bppz7WOA.js} +0 -0
  260. /package/client/dist/assets/{browser-C__Vz7KR.js → browser-0xeW8fUa2.js} +0 -0
  261. /package/client/dist/assets/{browser-EFmPpkvO.js → browser-543jbxE4.js} +0 -0
  262. /package/client/dist/assets/{browser-DhwTc0ry.js → browser-C9rUUxo4.js} +0 -0
  263. /package/client/dist/assets/{browser-C91MQBxx.js → browser-CEqx11iy.js} +0 -0
  264. /package/client/dist/assets/{browser-B7i7Ysc8.js → browser-CLC0etB_2.js} +0 -0
  265. /package/client/dist/assets/{browser-DwE289IS.js → browser-DyG2l9Wa.js} +0 -0
  266. /package/client/dist/assets/{browser-BVQgd1_1.js → browser-ExmELH702.js} +0 -0
  267. /package/client/dist/assets/{cameligo-BK_p0bgU.js → cameligo-0MRMdSmg.js} +0 -0
  268. /package/client/dist/assets/{chat-C5nJF6L0.js → chat-CCytD3P8.js} +0 -0
  269. /package/client/dist/assets/{chat-UMl6H55K.js → chat-CN8BMAMc.js} +0 -0
  270. /package/client/dist/assets/{chat-BXVx6rb5.js → chat-Cu6F3d6g2.js} +0 -0
  271. /package/client/dist/assets/{chat-CE8bx6Rz.js → chat-DagUyoVA.js} +0 -0
  272. /package/client/dist/assets/{chat-PVakYp92.js → chat-IjutwlBg.js} +0 -0
  273. /package/client/dist/assets/{chat-9RcD5Lcn.js → chat-NQPCBQo72.js} +0 -0
  274. /package/client/dist/assets/{chat-BnJPyeUK.js → chat-vVpwkOp52.js} +0 -0
  275. /package/client/dist/assets/{clojure-BQ7JOykv.js → clojure-B5dKj863.js} +0 -0
  276. /package/client/dist/assets/{clsx-CjLeUJfG.js → clsx-1dnHRn8W.js} +0 -0
  277. /package/client/dist/assets/{code-OoLqhjoI.js → code-32l6Naxu2.js} +0 -0
  278. /package/client/dist/assets/{code-Lg4awa35.js → code-BaG05zK62.js} +0 -0
  279. /package/client/dist/assets/{code-BPMR8_Vp.js → code-C5cibF2F.js} +0 -0
  280. /package/client/dist/assets/{code-aCUqkVN_.js → code-Ce-nBIwj.js} +0 -0
  281. /package/client/dist/assets/{code-BsOBm1Fb.js → code-Dap54vOb.js} +0 -0
  282. /package/client/dist/assets/{code-u9Sg9ohM.js → code-Dhb6jbAU.js} +0 -0
  283. /package/client/dist/assets/{code-eh4vO2-_.js → code-_NOCo-Ol2.js} +0 -0
  284. /package/client/dist/assets/{coffee-BD3DiL5s.js → coffee-DSbWjzk7.js} +0 -0
  285. /package/client/dist/assets/{common-C9VyfY7g.js → common-0aY9HQBP.js} +0 -0
  286. /package/client/dist/assets/{common-LDwESeCX.js → common-5jScBJqt.js} +0 -0
  287. /package/client/dist/assets/{common-ULlk84G4.js → common-BdaRciTu.js} +0 -0
  288. /package/client/dist/assets/{common-CzCQ0rpW.js → common-CHARW6MZ2.js} +0 -0
  289. /package/client/dist/assets/{common-CNoRVpnA.js → common-CQCJzAQq2.js} +0 -0
  290. /package/client/dist/assets/{common-Dmpyh323.js → common-DNhhqjlJ.js} +0 -0
  291. /package/client/dist/assets/{common-CcHFVATT.js → common-YdyZtmaI2.js} +0 -0
  292. /package/client/dist/assets/{cpp-splnCwCh.js → cpp-SBF8SAh9.js} +0 -0
  293. /package/client/dist/assets/{csharp-BCpsl-o3.js → csharp-Lzuq_1t-.js} +0 -0
  294. /package/client/dist/assets/{csp-tkCWrZmb.js → csp-BEzxZqi1.js} +0 -0
  295. /package/client/dist/assets/{css-B_xdnReq.js → css-C3D3PKln.js} +0 -0
  296. /package/client/dist/assets/{cypher-OL1zq-y3.js → cypher-CQ3dEPmv.js} +0 -0
  297. /package/client/dist/assets/{dart-CtTlOkrm.js → dart-DCPmxolI.js} +0 -0
  298. /package/client/dist/assets/{dashboard-C52PElPV.js → dashboard-BTiH361F.js} +0 -0
  299. /package/client/dist/assets/{dashboard-C-dXxut-.js → dashboard-COSm_14E.js} +0 -0
  300. /package/client/dist/assets/{dashboard-CUjyhohl.js → dashboard-CfOs70FN2.js} +0 -0
  301. /package/client/dist/assets/{dashboard-zH9quXks.js → dashboard-CzHDp14_2.js} +0 -0
  302. /package/client/dist/assets/{dashboard-03EpOoMM.js → dashboard-D6Woy2B5.js} +0 -0
  303. /package/client/dist/assets/{dashboard-C2owt3eN.js → dashboard-DwbH4oVH.js} +0 -0
  304. /package/client/dist/assets/{dashboard-Ch6H-457.js → dashboard-cWhU3krA2.js} +0 -0
  305. /package/client/dist/assets/{dockerfile-DcQ5CNiW.js → dockerfile-B_2_aaTO.js} +0 -0
  306. /package/client/dist/assets/{ecl-DZpiDRt6.js → ecl-rADUeXsV.js} +0 -0
  307. /package/client/dist/assets/{elixir-Dzj2lqtK.js → elixir-DOd-TuJO.js} +0 -0
  308. /package/client/dist/assets/{explore-CCcPXrHg.js → explore-B82VMUJ_.js} +0 -0
  309. /package/client/dist/assets/{explore-DQ0XEjed.js → explore-BGz1rvQE.js} +0 -0
  310. /package/client/dist/assets/{explore-xQoaak6e.js → explore-BzdMEpuf.js} +0 -0
  311. /package/client/dist/assets/{explore-B2n8r9Ye.js → explore-CbW0381i2.js} +0 -0
  312. /package/client/dist/assets/{explore-4SD1DxR0.js → explore-ChtxIiSM.js} +0 -0
  313. /package/client/dist/assets/{explore-BxR9q8Hq.js → explore-DfcUfiPw2.js} +0 -0
  314. /package/client/dist/assets/{explore-CZt4Ncpa.js → explore-yRF7wFSp2.js} +0 -0
  315. /package/client/dist/assets/{flow9-CFENCHIZ.js → flow9-Bf7zg_j0.js} +0 -0
  316. /package/client/dist/assets/{format-command-CMsBTOPN.js → format-command-D96da4fZ.js} +0 -0
  317. /package/client/dist/assets/{fsharp-D-4bv7FB.js → fsharp-BqROZjbA.js} +0 -0
  318. /package/client/dist/assets/{go-djxbTJq7.js → go-oQTP5uLe.js} +0 -0
  319. /package/client/dist/assets/{graphql-DHIFrkZ6.js → graphql-CSHfTU3q.js} +0 -0
  320. /package/client/dist/assets/{hcl-CXVoowNb.js → hcl-CeG-RoFJ.js} +0 -0
  321. /package/client/dist/assets/{ini-Crzc5kly.js → ini-B2Dv4ohc.js} +0 -0
  322. /package/client/dist/assets/{integrations-C7u7SInG.js → integrations-B0OBPU9_.js} +0 -0
  323. /package/client/dist/assets/{integrations-B17KyA-i.js → integrations-BA5pM05t.js} +0 -0
  324. /package/client/dist/assets/{integrations-DkBi-Gsh.js → integrations-BJvrlcc7.js} +0 -0
  325. /package/client/dist/assets/{integrations-DwSVdCpf.js → integrations-CPKYkG36.js} +0 -0
  326. /package/client/dist/assets/{integrations-A9f08E0o.js → integrations-CnrX7vqw2.js} +0 -0
  327. /package/client/dist/assets/{integrations-9qxUNhPD.js → integrations-DBou159M2.js} +0 -0
  328. /package/client/dist/assets/{integrations-B46ac3sf.js → integrations-DeJFRyXz2.js} +0 -0
  329. /package/client/dist/assets/{java-CYLaJrdE.js → java-aUDDeufb.js} +0 -0
  330. /package/client/dist/assets/{jira-Dht8qNck.js → jira-BDgxAFTF2.js} +0 -0
  331. /package/client/dist/assets/{jira-4Fin3fu7.js → jira-BwLBgmfI2.js} +0 -0
  332. /package/client/dist/assets/{jira-0ldfMByG.js → jira-D3GGzXOI.js} +0 -0
  333. /package/client/dist/assets/{jira-BpnpUFlb.js → jira-DeotPx6P2.js} +0 -0
  334. /package/client/dist/assets/{jira-DzIVvNmy.js → jira-NwlUCcQD.js} +0 -0
  335. /package/client/dist/assets/{jira-CBU0200d.js → jira-Srx2P5zS.js} +0 -0
  336. /package/client/dist/assets/{jira-01H1RfQj.js → jira-mi37H4Kt.js} +0 -0
  337. /package/client/dist/assets/{jobs-jEQidSIb.js → jobs-B56vQEkh2.js} +0 -0
  338. /package/client/dist/assets/{jobs-DM9owF1j.js → jobs-BYIk6Tg_.js} +0 -0
  339. /package/client/dist/assets/{jobs-Bw4hqEro.js → jobs-C-lM-iax2.js} +0 -0
  340. /package/client/dist/assets/{jobs-BF9raUkL.js → jobs-CYdevGgT.js} +0 -0
  341. /package/client/dist/assets/{jobs-ym72SIR9.js → jobs-D8adm2BX.js} +0 -0
  342. /package/client/dist/assets/{jobs-DcCONARH.js → jobs-K_Y8KAZ2.js} +0 -0
  343. /package/client/dist/assets/{jobs-Oz3UtLQn.js → jobs-OwM0ZWhI2.js} +0 -0
  344. /package/client/dist/assets/{julia-BJ7tUU-T.js → julia-C5LbruO5.js} +0 -0
  345. /package/client/dist/assets/{kotlin-CeWcU3lC.js → kotlin-C6mOuSKk.js} +0 -0
  346. /package/client/dist/assets/{less-CviwWNG4.js → less-D5qC3caW.js} +0 -0
  347. /package/client/dist/assets/{lexon-Dt28jqDS.js → lexon-Dr2La-fj.js} +0 -0
  348. /package/client/dist/assets/{loops-DE-2cmLw.js → loops-BDhEfnx82.js} +0 -0
  349. /package/client/dist/assets/{loops-mcoeFMat.js → loops-BM5QggwH.js} +0 -0
  350. /package/client/dist/assets/{loops-D_ZxkD4l.js → loops-CPjLAAxj.js} +0 -0
  351. /package/client/dist/assets/{loops-BYNUJVyD.js → loops-DKnk79TB2.js} +0 -0
  352. /package/client/dist/assets/{loops-B_gS4Pqu.js → loops-DLW0aFMm.js} +0 -0
  353. /package/client/dist/assets/{loops-Fv4Bs-9A.js → loops-Dcv3dFy_2.js} +0 -0
  354. /package/client/dist/assets/{loops-B_w7STrw.js → loops-y7wFRx6M.js} +0 -0
  355. /package/client/dist/assets/{lua-B6AOaJSi.js → lua-Zy6u5z6Z.js} +0 -0
  356. /package/client/dist/assets/{m3-VnMkHJcy.js → m3-C7XHeDz_.js} +0 -0
  357. /package/client/dist/assets/{markdown-8vKNdvIM.js → markdown-PiF7r-2h.js} +0 -0
  358. /package/client/dist/assets/{mips-DoEcuzan.js → mips-nn07GiyE.js} +0 -0
  359. /package/client/dist/assets/{msdax-CNzvHyEp.js → msdax-DaKFVMST.js} +0 -0
  360. /package/client/dist/assets/{mysql-Buk3vUtL.js → mysql-C6d6xrbU.js} +0 -0
  361. /package/client/dist/assets/{nav-Cw3_40fA.js → nav-1hj2izqB2.js} +0 -0
  362. /package/client/dist/assets/{nav-DNDJ3H-_.js → nav-BBUKMAu-2.js} +0 -0
  363. /package/client/dist/assets/{nav-CrG_mYRr.js → nav-CLqkP-26.js} +0 -0
  364. /package/client/dist/assets/{nav-DVp1nEsi.js → nav-Cv46L837.js} +0 -0
  365. /package/client/dist/assets/{nav-DbAbG5_k.js → nav-DgA-rjLk2.js} +0 -0
  366. /package/client/dist/assets/{nav-B5W9IMnf.js → nav-EG2pr6vN.js} +0 -0
  367. /package/client/dist/assets/{nav-_0vAgZ_k.js → nav-r3mIJVfU.js} +0 -0
  368. /package/client/dist/assets/{objective-c-DfOmda-5.js → objective-c-B6KMtI-k.js} +0 -0
  369. /package/client/dist/assets/{pascal-DoAA2yjy.js → pascal-DYr8MPE7.js} +0 -0
  370. /package/client/dist/assets/{pascaligo-C65Vn1fu.js → pascaligo-B3pd-jJ_.js} +0 -0
  371. /package/client/dist/assets/{perl-INlfQ_ro.js → perl-z2xUzoaL.js} +0 -0
  372. /package/client/dist/assets/{pgsql-DtwRzglx.js → pgsql-DUvT-09-.js} +0 -0
  373. /package/client/dist/assets/{php-DfHqVNet.js → php-CGyOmJfy.js} +0 -0
  374. /package/client/dist/assets/{pla-D3dNVRYk.js → pla-CMqgvyD0.js} +0 -0
  375. /package/client/dist/assets/{postiats-UKXD1rM4.js → postiats-Dx5LUn4Z.js} +0 -0
  376. /package/client/dist/assets/{powerquery-zE3E3O7s.js → powerquery-DazYxvJ6.js} +0 -0
  377. /package/client/dist/assets/{powershell-Df9b3zQl.js → powershell-B3nwlDka.js} +0 -0
  378. /package/client/dist/assets/{protobuf-BF0nUVrW.js → protobuf-BGuu2u2s.js} +0 -0
  379. /package/client/dist/assets/{pug-Bj6Yikv_.js → pug-Dbte1MXA.js} +0 -0
  380. /package/client/dist/assets/{qsharp-BI4h-raZ.js → qsharp-DJLwBOvG.js} +0 -0
  381. /package/client/dist/assets/{r-DhpnmaXx.js → r-DmGBRSHj.js} +0 -0
  382. /package/client/dist/assets/{redis-DwYYPr4d.js → redis-VvUYn0a4.js} +0 -0
  383. /package/client/dist/assets/{redshift-D2f3Bc-4.js → redshift-6GdDrxg3.js} +0 -0
  384. /package/client/dist/assets/{restructuredtext-Dkiif6fe.js → restructuredtext-CfAB8aRU.js} +0 -0
  385. /package/client/dist/assets/{ruby-C6hLmHy0.js → ruby-CIYK6MXY.js} +0 -0
  386. /package/client/dist/assets/{rust-X8WAGtxB.js → rust-CTHZfjj9.js} +0 -0
  387. /package/client/dist/assets/{sb-4M2la0Kr.js → sb-CkKTdkz_.js} +0 -0
  388. /package/client/dist/assets/{scala-CaCXz58E.js → scala-Bx-Wr9TM.js} +0 -0
  389. /package/client/dist/assets/{scheme-CMdjpmP7.js → scheme-Dcfi6f83.js} +0 -0
  390. /package/client/dist/assets/{scss-QopmvPyp.js → scss-ByL-7PFQ.js} +0 -0
  391. /package/client/dist/assets/{shell-CDBchS00.js → shell-Csnb9Yqd.js} +0 -0
  392. /package/client/dist/assets/{solidity-DvBfi5mC.js → solidity-Dbw5-0QP.js} +0 -0
  393. /package/client/dist/assets/{sophia-HSnXR17u.js → sophia-ZQ3saZQx.js} +0 -0
  394. /package/client/dist/assets/{sparql-DhG_ppup.js → sparql-BEtOel8u.js} +0 -0
  395. /package/client/dist/assets/{specs-CUE3xSFM.js → specs-B5XOoH-02.js} +0 -0
  396. /package/client/dist/assets/{specs-C2wW5bq8.js → specs-B8mwScoM2.js} +0 -0
  397. /package/client/dist/assets/{specs-Bku8SypT.js → specs-Bj_3fDrQ.js} +0 -0
  398. /package/client/dist/assets/{specs-CnH7dOiF.js → specs-CWNKAScX2.js} +0 -0
  399. /package/client/dist/assets/{specs-BvsFNKTs.js → specs-D4z5d8uq.js} +0 -0
  400. /package/client/dist/assets/{specs-D4ORogcT.js → specs-DgvIRZtM.js} +0 -0
  401. /package/client/dist/assets/{specs-D6Y76Bgi.js → specs-DuRzE5wE.js} +0 -0
  402. /package/client/dist/assets/{sql-DHeIS-tf.js → sql-DGPDbzB7.js} +0 -0
  403. /package/client/dist/assets/{st-CMWchiRU.js → st-GeW2MOgh.js} +0 -0
  404. /package/client/dist/assets/{swift-CDXvBefj.js → swift-BVYTN8jq.js} +0 -0
  405. /package/client/dist/assets/{systemverilog-0RTukYUE.js → systemverilog-Deg2a8Lr.js} +0 -0
  406. /package/client/dist/assets/{tcl-CbBF_Ttl.js → tcl-6DnLmROF.js} +0 -0
  407. /package/client/dist/assets/{terminal-BLh00ouM.js → terminal-B2sExUis.js} +0 -0
  408. /package/client/dist/assets/{terminal-Cz_Puz0q.js → terminal-CH0fdHvP.js} +0 -0
  409. /package/client/dist/assets/{terminal-DFEH9XTQ.js → terminal-CPMigUX7.js} +0 -0
  410. /package/client/dist/assets/{terminal-CB33IsO1.js → terminal-DOwfkxqa2.js} +0 -0
  411. /package/client/dist/assets/{terminal-CR6t-Oey.js → terminal-DjSSa5qP.js} +0 -0
  412. /package/client/dist/assets/{terminal-CY_sPfdD.js → terminal-DoMTHedv2.js} +0 -0
  413. /package/client/dist/assets/{terminal-BTanJIt_.js → terminal-w0i-OCp32.js} +0 -0
  414. /package/client/dist/assets/{tickets-D6f3GSYn.js → tickets-CQTana1u.js} +0 -0
  415. /package/client/dist/assets/{tickets-blQnNA4N.js → tickets-D00mSt832.js} +0 -0
  416. /package/client/dist/assets/{tickets-68LH1xp6.js → tickets-D7CSuWjO.js} +0 -0
  417. /package/client/dist/assets/{tickets-OrJwUxJR.js → tickets-Dq7HDy8n.js} +0 -0
  418. /package/client/dist/assets/{tickets-PtHNxQo5.js → tickets-DvbFg_-c2.js} +0 -0
  419. /package/client/dist/assets/{tickets-REr-EQx9.js → tickets-heDAaj8C2.js} +0 -0
  420. /package/client/dist/assets/{tickets-jxsTrApR.js → tickets-onKZz6Dd.js} +0 -0
  421. /package/client/dist/assets/{twig-DCcGd8FE.js → twig-XbbXW9Yz.js} +0 -0
  422. /package/client/dist/assets/{typespec-HTphp-Uh.js → typespec-CRlV8GhI.js} +0 -0
  423. /package/client/dist/assets/{vb-Cb_yUcVd.js → vb-BHE2izPH.js} +0 -0
  424. /package/client/dist/assets/{wgsl-DrKU3YXj.js → wgsl-Bf5vkfmY.js} +0 -0
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAgentConversation = createAgentConversation;
4
+ exports.getAgentConversation = getAgentConversation;
5
+ exports.listAgentConversations = listAgentConversations;
6
+ exports.updateAgentConversation = updateAgentConversation;
7
+ exports.deleteAgentConversation = deleteAgentConversation;
8
+ exports.addAgentMessage = addAgentMessage;
9
+ exports.listAgentMessages = listAgentMessages;
10
+ const crypto_1 = require("crypto");
11
+ const agent_tier_1 = require("./agent-tier");
12
+ function mapConversation(row) {
13
+ if (!row)
14
+ return undefined;
15
+ return { ...row, tier_level: (0, agent_tier_1.normalizeLevel)(row.tier_level) };
16
+ }
17
+ function createAgentConversation(db, input = {}) {
18
+ 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);
21
+ return getAgentConversation(db, id);
22
+ }
23
+ function getAgentConversation(db, id) {
24
+ return mapConversation(db.prepare('SELECT * FROM agent_conversations WHERE id = ?').get(id));
25
+ }
26
+ function listAgentConversations(db, limit = 100) {
27
+ return db
28
+ .prepare('SELECT * FROM agent_conversations ORDER BY updated_at DESC LIMIT ?')
29
+ .all(limit).map((r) => mapConversation(r));
30
+ }
31
+ /** Patch a conversation. Only the provided fields change; `updated_at` always bumps. */
32
+ function updateAgentConversation(db, id, patch) {
33
+ const sets = [];
34
+ const vals = [];
35
+ for (const [k, v] of Object.entries(patch)) {
36
+ sets.push(`${k} = ?`);
37
+ vals.push(v);
38
+ }
39
+ sets.push("updated_at = datetime('now')");
40
+ if (sets.length > 0) {
41
+ db.prepare(`UPDATE agent_conversations SET ${sets.join(', ')} WHERE id = ?`).run(...vals, id);
42
+ }
43
+ return getAgentConversation(db, id);
44
+ }
45
+ function deleteAgentConversation(db, id) {
46
+ db.prepare('DELETE FROM agent_conversations WHERE id = ?').run(id);
47
+ }
48
+ function addAgentMessage(db, input) {
49
+ 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);
51
+ // Touch the parent so the list stays ordered by latest activity.
52
+ 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);
54
+ }
55
+ function listAgentMessages(db, conversationId) {
56
+ return db
57
+ .prepare('SELECT * FROM agent_messages WHERE conversation_id = ? ORDER BY created_at ASC, rowid ASC')
58
+ .all(conversationId);
59
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AGENT_PROJECT_ENV = exports.AGENT_PROJECT_HEADER = exports.AGENT_TIER_ENV = exports.AGENT_TIER_HEADER = exports.AGENT_TIER_NAMES = void 0;
4
+ exports.tierNameForLevel = tierNameForLevel;
5
+ exports.levelForTierName = levelForTierName;
6
+ exports.normalizeLevel = normalizeLevel;
7
+ exports.nextLevel = nextLevel;
8
+ exports.levelAllowsTier = levelAllowsTier;
9
+ exports.levelFromHeader = levelFromHeader;
10
+ exports.tierNeedsApproval = tierNeedsApproval;
11
+ exports.AGENT_TIER_NAMES = [
12
+ 'observe',
13
+ 'edit',
14
+ 'operate',
15
+ 'autonomous',
16
+ ];
17
+ /** The HTTP header the agent's MCP bridge sets so the tool guard can read the level. */
18
+ exports.AGENT_TIER_HEADER = 'x-specrails-agent-tier';
19
+ /** Env var the AgentChatManager sets on the bridge spawn; the bridge forwards it as the header. */
20
+ exports.AGENT_TIER_ENV = 'SPECRAILS_AGENT_TIER';
21
+ /** Header carrying the pinned project id so tools resolve it per-request. */
22
+ exports.AGENT_PROJECT_HEADER = 'x-specrails-active-project';
23
+ /** Env var the manager sets on the bridge spawn; the bridge forwards it as the project header. */
24
+ exports.AGENT_PROJECT_ENV = 'SPECRAILS_ACTIVE_PROJECT';
25
+ /** Which MCP tiers a given ladder level unlocks (cumulative). */
26
+ const TIERS_BY_LEVEL = {
27
+ 0: new Set(['read']),
28
+ 1: new Set(['read', 'write']),
29
+ 2: new Set(['read', 'write', 'ai-spawn']),
30
+ 3: new Set(['read', 'write', 'ai-spawn', 'destructive']),
31
+ };
32
+ function tierNameForLevel(level) {
33
+ return exports.AGENT_TIER_NAMES[level];
34
+ }
35
+ function levelForTierName(name) {
36
+ const idx = exports.AGENT_TIER_NAMES.indexOf(name);
37
+ return idx === -1 ? null : idx;
38
+ }
39
+ /** Clamp an arbitrary number/string to a valid ladder level (default observe). */
40
+ function normalizeLevel(value) {
41
+ const n = typeof value === 'string' ? Number(value) : value;
42
+ if (typeof n === 'number' && Number.isInteger(n) && n >= 0 && n <= 3) {
43
+ return n;
44
+ }
45
+ // Allow the name form too.
46
+ if (typeof value === 'string') {
47
+ const byName = levelForTierName(value);
48
+ if (byName !== null)
49
+ return byName;
50
+ }
51
+ return 0;
52
+ }
53
+ /** Cycle Shift+Tab: 0→1→2→3→0. */
54
+ function nextLevel(level) {
55
+ return ((level + 1) % 4);
56
+ }
57
+ /** True when the given MCP tier is permitted at the given ladder level. */
58
+ function levelAllowsTier(level, tier) {
59
+ return TIERS_BY_LEVEL[level].has(tier);
60
+ }
61
+ /**
62
+ * Parse the agent-tier header value into a level, or null when absent/invalid.
63
+ * The header carries the tier NAME (observe/edit/operate/autonomous) or the
64
+ * numeric level; anything else yields null (→ fall back to Settings tiers).
65
+ */
66
+ function levelFromHeader(headerValue) {
67
+ if (headerValue == null)
68
+ return null;
69
+ const raw = Array.isArray(headerValue) ? headerValue[0] : headerValue;
70
+ if (typeof raw !== 'string' || raw.trim() === '')
71
+ return null;
72
+ const byName = levelForTierName(raw.trim());
73
+ if (byName !== null)
74
+ return byName;
75
+ const n = Number(raw.trim());
76
+ if (Number.isInteger(n) && n >= 0 && n <= 3)
77
+ return n;
78
+ return null;
79
+ }
80
+ /**
81
+ * Whether a cost/destructive action needs an explicit inline approval (Option C):
82
+ * reversible writes (read/write) run silently; ai-spawn and destructive prompt.
83
+ */
84
+ function tierNeedsApproval(tier) {
85
+ return tier === 'ai-spawn' || tier === 'destructive';
86
+ }
@@ -351,6 +351,33 @@ function applyDesktopMigrations(db) {
351
351
  ('seed-min-coverage', 'MIN_COVERAGE', '80');
352
352
  `);
353
353
  },
354
+ // 17: app-global agent chat (design D2). The agent chat lives ABOVE projects,
355
+ // so its conversations are stored in the app registry DB (not any per-project
356
+ // jobs.sqlite). `pinned_project_id` records the Cursor-style selector target
357
+ // (NULL = Home / app-global); `tier_level` records the Shift+Tab ladder.
358
+ () => {
359
+ db.exec(`
360
+ CREATE TABLE IF NOT EXISTS agent_conversations (
361
+ id TEXT PRIMARY KEY,
362
+ title TEXT,
363
+ provider TEXT NOT NULL DEFAULT 'claude',
364
+ model TEXT,
365
+ session_id TEXT,
366
+ pinned_project_id TEXT,
367
+ tier_level INTEGER NOT NULL DEFAULT 0,
368
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
369
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
370
+ );
371
+ CREATE TABLE IF NOT EXISTS agent_messages (
372
+ id TEXT PRIMARY KEY,
373
+ conversation_id TEXT NOT NULL REFERENCES agent_conversations(id) ON DELETE CASCADE,
374
+ role TEXT NOT NULL,
375
+ content TEXT NOT NULL,
376
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
377
+ );
378
+ CREATE INDEX IF NOT EXISTS idx_agent_messages_conv ON agent_messages(conversation_id, created_at);
379
+ `);
380
+ },
354
381
  ];
355
382
  for (let i = 0; i < migrations.length; i++) {
356
383
  const version = i + 1;
@@ -23,6 +23,9 @@ const terminal_manager_1 = require("./terminal-manager");
23
23
  const terminal_shell_integration_1 = require("./terminal-shell-integration");
24
24
  const feature_flags_1 = require("./feature-flags");
25
25
  const mobile_1 = require("./mobile");
26
+ const mcp_1 = require("./mcp");
27
+ const agent_chat_manager_1 = require("./agent-chat-manager");
28
+ const agent_chat_router_1 = require("./agent-chat-router");
26
29
  const browser_playwright_1 = require("./browser-playwright");
27
30
  const telemetry_receiver_1 = require("./telemetry-receiver");
28
31
  const telemetry_compactor_1 = require("./telemetry-compactor");
@@ -150,6 +153,20 @@ app.use(corsMiddleware);
150
153
  // 12mb limit FIRST — once it sets req._body the global parser below no-ops for
151
154
  // these paths. (The actual /otlp router still requires loopback.)
152
155
  app.use('/otlp', express_1.default.json({ limit: '12mb' }));
156
+ // ─── MCP streamable-HTTP transport (design D1) ───────────────────────────────
157
+ // Mounted BEFORE the global express.json so it claims `/api/mcp` with a larger
158
+ // body limit (req._body makes the global parser no-op for this path), and
159
+ // BEFORE `app.use('/api', requireAuth)` so it uses the SCOPED mcp token via
160
+ // requireMcpAuth rather than inheriting the all-powerful master token. The
161
+ // dispatcher delegates to the McpServerManager constructed during Super-mode
162
+ // bootstrap (lazily referenced — it exists by request time).
163
+ app.use('/api/mcp', express_1.default.json({ limit: '4mb' }), auth_1.requireLoopback, mcp_1.requireMcpAuth, (req, res) => {
164
+ if (_mcpManager) {
165
+ void _mcpManager.handleHttp(req, res);
166
+ return;
167
+ }
168
+ res.status(503).json({ jsonrpc: '2.0', error: { code: -32000, message: 'MCP transport not ready' }, id: null });
169
+ });
153
170
  app.use(express_1.default.json({ limit: '1mb' }));
154
171
  const server = http_1.default.createServer(app);
155
172
  const wsServerOptions = {
@@ -219,6 +236,8 @@ let _getProjectCount = () => 0;
219
236
  let _registry = null;
220
237
  /** The mobile companion gateway (off by default); torn down on shutdown. */
221
238
  let _mobileGateway = null;
239
+ let _mcpManager = null;
240
+ let _agentChatManager = null;
222
241
  server.on('upgrade', (request, socket, head) => {
223
242
  const urlStr = request.url ?? '/';
224
243
  const auth = authorizeUpgrade(request);
@@ -507,6 +526,23 @@ function applyPtyWsRateLimiting(ws) {
507
526
  if (mobileGateway.isEnabledSetting()) {
508
527
  mobileGateway.start().catch((err) => console.error('[mobile-gateway] boot start failed:', err));
509
528
  }
529
+ // ─── Embedded MCP server (the /api/mcp transport mounted above) ─────────────
530
+ const mcpManager = new mcp_1.McpServerManager({ registry, broadcast, desktopPort: port, version: PKG_VERSION });
531
+ _mcpManager = mcpManager;
532
+ // Loopback + master-token control plane for the Settings ▸ MCP panel.
533
+ app.use('/api/mcp-admin', auth_1.requireLoopback, (0, mcp_1.createMcpAdminRouter)({
534
+ manager: mcpManager,
535
+ desktopDb: registry.desktopDb,
536
+ desktopPort: port,
537
+ broadcast,
538
+ }));
539
+ if (mcpManager.isEnabledSetting()) {
540
+ mcpManager.start().catch((err) => console.error('[mcp] boot start failed:', err));
541
+ }
542
+ // ─── App-global agent chat (drives the app via its own MCP) ────────────────
543
+ const agentChatManager = new agent_chat_manager_1.AgentChatManager(broadcast, registry.desktopDb, port);
544
+ _agentChatManager = agentChatManager;
545
+ app.use('/api/agent', (0, agent_chat_router_1.createAgentChatRouter)({ manager: agentChatManager, desktopDb: registry.desktopDb }));
510
546
  // App-level routes. CRITICAL mount order: the desktop router is mounted at
511
547
  // '/api' BEFORE the project router below so its exact routes (e.g.
512
548
  // GET /api/projects, DELETE /api/projects/:id) are handled here, while
@@ -611,6 +647,8 @@ async function shutdown() {
611
647
  catch { /* ignore */ }
612
648
  try {
613
649
  await _mobileGateway?.stop();
650
+ await _mcpManager?.stop();
651
+ await _agentChatManager?.shutdown();
614
652
  }
615
653
  catch { /* ignore */ }
616
654
  try {
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ // The platform guide returned by the `specrails_guide` meta tool and the
3
+ // `specrails://guide` resource. This is what lets an external LLM "understand
4
+ // the platform" without prior knowledge. It is intentionally English (the LLM
5
+ // consumes it); human-facing onboarding docs are localized separately.
6
+ //
7
+ // Keep this BYTE-STABLE where possible (no timestamps / live data) so MCP
8
+ // clients that cache resources stay valid.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.SPECRAILS_GUIDE = void 0;
11
+ exports.SPECRAILS_GUIDE = `# Specrails Desktop — Agent Guide
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.
16
+
17
+ ## Core concepts
18
+
19
+ - **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.
37
+ - **Plugin**: an MCP-based integration installed per project (e.g. serena).
38
+
39
+ ## Async results (IMPORTANT)
40
+
41
+ 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.
47
+
48
+ ## Permission tiers
49
+
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.
55
+
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.
58
+
59
+ ## Claude-only features
60
+
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.
63
+
64
+ ## Typical workflow
65
+
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.
76
+
77
+ ## Resources
78
+
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).
82
+ `;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildToolSpecs = exports.TIER_SETTING_KEY = exports.MCP_ENABLED_KEY = exports.MCP_TIERS = exports.isTierEnabled = exports.isMcpEnabled = exports._resetMcpTokenForTest = exports.loadOrGenerateMcpToken = exports.regenerateMcpToken = exports.getMcpToken = exports.requireMcpAuth = exports.createMcpAdminRouter = exports.McpServerManager = void 0;
4
+ var mcp_server_1 = require("./mcp-server");
5
+ Object.defineProperty(exports, "McpServerManager", { enumerable: true, get: function () { return mcp_server_1.McpServerManager; } });
6
+ var mcp_admin_router_1 = require("./mcp-admin-router");
7
+ Object.defineProperty(exports, "createMcpAdminRouter", { enumerable: true, get: function () { return mcp_admin_router_1.createMcpAdminRouter; } });
8
+ var mcp_token_1 = require("./mcp-token");
9
+ Object.defineProperty(exports, "requireMcpAuth", { enumerable: true, get: function () { return mcp_token_1.requireMcpAuth; } });
10
+ Object.defineProperty(exports, "getMcpToken", { enumerable: true, get: function () { return mcp_token_1.getMcpToken; } });
11
+ Object.defineProperty(exports, "regenerateMcpToken", { enumerable: true, get: function () { return mcp_token_1.regenerateMcpToken; } });
12
+ Object.defineProperty(exports, "loadOrGenerateMcpToken", { enumerable: true, get: function () { return mcp_token_1.loadOrGenerateMcpToken; } });
13
+ Object.defineProperty(exports, "_resetMcpTokenForTest", { enumerable: true, get: function () { return mcp_token_1._resetMcpTokenForTest; } });
14
+ var mcp_tiers_1 = require("./mcp-tiers");
15
+ Object.defineProperty(exports, "isMcpEnabled", { enumerable: true, get: function () { return mcp_tiers_1.isMcpEnabled; } });
16
+ Object.defineProperty(exports, "isTierEnabled", { enumerable: true, get: function () { return mcp_tiers_1.isTierEnabled; } });
17
+ Object.defineProperty(exports, "MCP_TIERS", { enumerable: true, get: function () { return mcp_tiers_1.MCP_TIERS; } });
18
+ Object.defineProperty(exports, "MCP_ENABLED_KEY", { enumerable: true, get: function () { return mcp_tiers_1.MCP_ENABLED_KEY; } });
19
+ Object.defineProperty(exports, "TIER_SETTING_KEY", { enumerable: true, get: function () { return mcp_tiers_1.TIER_SETTING_KEY; } });
20
+ var catalog_1 = require("./tools/catalog");
21
+ Object.defineProperty(exports, "buildToolSpecs", { enumerable: true, get: function () { return catalog_1.buildToolSpecs; } });
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMcpAdminRouter = createMcpAdminRouter;
4
+ const express_1 = require("express");
5
+ const mcp_token_1 = require("./mcp-token");
6
+ const desktop_db_1 = require("../desktop-db");
7
+ const mcp_tiers_1 = require("./mcp-tiers");
8
+ function tierState(db) {
9
+ return {
10
+ write: (0, mcp_tiers_1.isTierEnabled)(db, 'write'),
11
+ aiSpawn: (0, mcp_tiers_1.isTierEnabled)(db, 'ai-spawn'),
12
+ destructive: (0, mcp_tiers_1.isTierEnabled)(db, 'destructive'),
13
+ };
14
+ }
15
+ function redact(token) {
16
+ return token.length > 4 ? `…${token.slice(-4)}` : '…';
17
+ }
18
+ function createMcpAdminRouter(deps) {
19
+ const router = (0, express_1.Router)();
20
+ const { manager, desktopDb, desktopPort } = deps;
21
+ router.get('/status', (_req, res) => {
22
+ res.json({ ...manager.status(), tiers: tierState(desktopDb), tokenHint: redact((0, mcp_token_1.getMcpToken)()) });
23
+ });
24
+ router.post('/enable', async (_req, res) => {
25
+ try {
26
+ res.json(await manager.setEnabled(true));
27
+ }
28
+ catch (err) {
29
+ res.status(409).json({ error: err instanceof Error ? err.message : 'Failed to enable MCP' });
30
+ }
31
+ });
32
+ router.post('/disable', async (_req, res) => {
33
+ res.json(await manager.setEnabled(false));
34
+ });
35
+ // Update the opt-in permission tiers (read is always on, not settable here).
36
+ router.patch('/tiers', (req, res) => {
37
+ const body = (req.body ?? {});
38
+ const fields = [
39
+ ['write', 'write'],
40
+ ['aiSpawn', 'ai-spawn'],
41
+ ['destructive', 'destructive'],
42
+ ];
43
+ for (const [bodyKey, tier] of fields) {
44
+ if (bodyKey in body) {
45
+ if (typeof body[bodyKey] !== 'boolean') {
46
+ res.status(400).json({ error: `${bodyKey} must be a boolean` });
47
+ return;
48
+ }
49
+ (0, desktop_db_1.setDesktopSetting)(desktopDb, mcp_tiers_1.TIER_SETTING_KEY[tier], body[bodyKey] ? 'true' : 'false');
50
+ }
51
+ }
52
+ res.json({ ok: true, tiers: tierState(desktopDb) });
53
+ });
54
+ // The full token — deliberately a separate loopback-only action so it never
55
+ // leaks through a general settings payload. Used by the panel's copy button.
56
+ router.get('/token', (_req, res) => {
57
+ res.json({ token: (0, mcp_token_1.getMcpToken)() });
58
+ });
59
+ router.post('/regenerate-token', (_req, res) => {
60
+ res.json({ token: (0, mcp_token_1.regenerateMcpToken)() });
61
+ });
62
+ // Connection info for the panel to render a ready-to-paste client config.
63
+ router.get('/config', (_req, res) => {
64
+ res.json({
65
+ httpUrl: `http://127.0.0.1:${desktopPort}/api/mcp`,
66
+ bridgeCommand: 'specrails-mcp',
67
+ hasToken: true,
68
+ });
69
+ });
70
+ return router;
71
+ }
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpServerManager = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
6
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
7
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
8
+ const mobile_event_bus_1 = require("../mobile/mobile-event-bus");
9
+ const mcp_tiers_1 = require("./mcp-tiers");
10
+ const desktop_db_1 = require("../desktop-db");
11
+ const catalog_1 = require("./tools/catalog");
12
+ const types_1 = require("./tools/types");
13
+ const resources_1 = require("./resources");
14
+ function jsonRpcError(message, code = -32000) {
15
+ return { jsonrpc: '2.0', error: { code, message }, id: null };
16
+ }
17
+ /**
18
+ * Embedded MCP server manager. Mirrors the MobileGateway lifecycle shape
19
+ * (isEnabledSetting / setEnabled / start / stop / status) but mounts on the
20
+ * EXISTING Express app rather than binding a second port. Uses the SDK's
21
+ * stateful streamable-HTTP transport (a transport per MCP session).
22
+ */
23
+ class McpServerManager {
24
+ _ctx;
25
+ _version;
26
+ _transports = {};
27
+ _toolCount;
28
+ constructor(deps) {
29
+ this._ctx = {
30
+ registry: deps.registry,
31
+ desktopDb: deps.registry.desktopDb,
32
+ broadcast: deps.broadcast,
33
+ eventBus: deps.eventBus ?? (0, mobile_event_bus_1.getMobileEventBus)(),
34
+ desktopPort: deps.desktopPort,
35
+ };
36
+ this._version = deps.version ?? '1.0.0';
37
+ this._toolCount = (0, catalog_1.buildToolSpecs)().length;
38
+ }
39
+ isEnabledSetting() {
40
+ return (0, mcp_tiers_1.isMcpEnabled)(this._ctx.desktopDb);
41
+ }
42
+ /** Persist the enable flag and tear down sessions when disabling. */
43
+ async setEnabled(enabled) {
44
+ (0, desktop_db_1.setDesktopSetting)(this._ctx.desktopDb, mcp_tiers_1.MCP_ENABLED_KEY, enabled ? 'true' : 'false');
45
+ if (!enabled)
46
+ await this.stop();
47
+ this._ctx.broadcast({ type: 'mcp.state', enabled, running: enabled });
48
+ return this.status();
49
+ }
50
+ // Mounting happens on the shared app, so start() has no port to bind; it
51
+ // exists for lifecycle symmetry with MobileGateway. The transport only serves
52
+ // when isEnabledSetting() is true (checked in handleHttp).
53
+ async start() {
54
+ /* no-op: served on the shared app, gated by isEnabledSetting() */
55
+ }
56
+ /** Close all open MCP sessions. */
57
+ async stop() {
58
+ for (const sid of Object.keys(this._transports)) {
59
+ try {
60
+ await this._transports[sid].close();
61
+ }
62
+ catch {
63
+ /* ignore */
64
+ }
65
+ delete this._transports[sid];
66
+ }
67
+ }
68
+ status() {
69
+ return {
70
+ enabled: this.isEnabledSetting(),
71
+ running: this.isEnabledSetting(),
72
+ activeSessions: Object.keys(this._transports).length,
73
+ toolCount: this._toolCount,
74
+ };
75
+ }
76
+ /** Build a fresh McpServer with the full tool + resource catalog registered. */
77
+ buildServer() {
78
+ const server = new mcp_js_1.McpServer({ name: 'specrails-desktop', version: this._version }, { capabilities: { logging: {}, tools: {}, resources: {} } });
79
+ for (const spec of (0, catalog_1.buildToolSpecs)()) {
80
+ (0, types_1.registerTieredTool)(server, this._ctx, spec);
81
+ }
82
+ (0, resources_1.registerResources)(server, this._ctx);
83
+ return server;
84
+ }
85
+ /**
86
+ * Express handler for the `/api/mcp` streamable-HTTP endpoint. Stateful:
87
+ * an initialize POST mints a session + transport; subsequent POST/GET/DELETE
88
+ * carry the `mcp-session-id` header.
89
+ */
90
+ async handleHttp(req, res) {
91
+ if (!this.isEnabledSetting()) {
92
+ res.status(404).json(jsonRpcError('MCP is disabled. Enable it in the Specrails app under Settings ▸ MCP.', -32004));
93
+ return;
94
+ }
95
+ const sessionId = req.headers['mcp-session-id'];
96
+ try {
97
+ if (req.method === 'POST') {
98
+ let transport = sessionId ? this._transports[sessionId] : undefined;
99
+ if (!transport) {
100
+ if (sessionId) {
101
+ res.status(400).json(jsonRpcError('Unknown or expired MCP session. Reinitialize.'));
102
+ return;
103
+ }
104
+ if (!(0, types_js_1.isInitializeRequest)(req.body)) {
105
+ res.status(400).json(jsonRpcError('Missing mcp-session-id and body is not an initialize request.'));
106
+ return;
107
+ }
108
+ transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
109
+ sessionIdGenerator: () => (0, crypto_1.randomUUID)(),
110
+ onsessioninitialized: (sid) => {
111
+ this._transports[sid] = transport;
112
+ },
113
+ });
114
+ transport.onclose = () => {
115
+ const sid = transport?.sessionId;
116
+ if (sid && this._transports[sid])
117
+ delete this._transports[sid];
118
+ };
119
+ const server = this.buildServer();
120
+ await server.connect(transport);
121
+ }
122
+ await transport.handleRequest(req, res, req.body);
123
+ return;
124
+ }
125
+ if (req.method === 'GET' || req.method === 'DELETE') {
126
+ const transport = sessionId ? this._transports[sessionId] : undefined;
127
+ if (!transport) {
128
+ res.status(400).json(jsonRpcError('Missing or unknown mcp-session-id.'));
129
+ return;
130
+ }
131
+ await transport.handleRequest(req, res);
132
+ return;
133
+ }
134
+ res.status(405).json(jsonRpcError('Method not allowed.'));
135
+ }
136
+ catch (err) {
137
+ if (!res.headersSent) {
138
+ res.status(500).json(jsonRpcError(err instanceof Error ? err.message : 'Internal MCP error', -32603));
139
+ }
140
+ }
141
+ }
142
+ }
143
+ exports.McpServerManager = McpServerManager;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCP_ENABLED_KEY = exports.TIER_SETTING_KEY = exports.MCP_TIERS = void 0;
4
+ exports.isMcpEnabled = isMcpEnabled;
5
+ exports.isTierEnabled = isTierEnabled;
6
+ exports.tierLabel = tierLabel;
7
+ exports.tierRefusalMessage = tierRefusalMessage;
8
+ const desktop_db_1 = require("../desktop-db");
9
+ exports.MCP_TIERS = ['read', 'write', 'ai-spawn', 'destructive'];
10
+ /** desktop_settings keys for the opt-in tiers (read is implicit). */
11
+ exports.TIER_SETTING_KEY = {
12
+ write: 'mcp_tier_write',
13
+ 'ai-spawn': 'mcp_tier_ai_spawn',
14
+ destructive: 'mcp_tier_destructive',
15
+ };
16
+ exports.MCP_ENABLED_KEY = 'mcp_enabled';
17
+ /** True when MCP itself is enabled (default false). */
18
+ function isMcpEnabled(db) {
19
+ return (0, desktop_db_1.getDesktopSetting)(db, exports.MCP_ENABLED_KEY) === 'true';
20
+ }
21
+ /**
22
+ * True when a tool of the given tier may run right now. Read is always allowed
23
+ * (its availability is governed by MCP being enabled, checked at the transport
24
+ * gate). The other tiers require their opt-in flag to be 'true'.
25
+ */
26
+ function isTierEnabled(db, tier) {
27
+ if (tier === 'read')
28
+ return true;
29
+ return (0, desktop_db_1.getDesktopSetting)(db, exports.TIER_SETTING_KEY[tier]) === 'true';
30
+ }
31
+ /** Human-readable label for a tier, used in refusal messages. */
32
+ function tierLabel(tier) {
33
+ switch (tier) {
34
+ case 'read':
35
+ return 'Read';
36
+ case 'write':
37
+ return 'Write';
38
+ case 'ai-spawn':
39
+ return 'AI-spawn (cost-incurring)';
40
+ case 'destructive':
41
+ return 'Destructive';
42
+ }
43
+ }
44
+ /** The message returned when a tool is refused because its tier is disabled. */
45
+ function tierRefusalMessage(tier) {
46
+ return (`This action requires the "${tierLabel(tier)}" permission tier, which is currently disabled. ` +
47
+ `Enable it in the Specrails app under Settings ▸ MCP, then retry.`);
48
+ }