specrails-desktop 2.17.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.
- package/client/dist/assets/{ActivityFeedPage-BLDMBgwL.js → ActivityFeedPage-mGnv5SOe.js} +1 -1
- package/client/dist/assets/AgentsPage-BH1isg5j.js +86 -0
- package/client/dist/assets/AnalyticsPage-ByyshYRI.js +1 -0
- package/client/dist/assets/{BarChart-ouivqe5L.js → BarChart-BqHUOnl9.js} +4 -4
- package/client/dist/assets/CodePage-CU7T_HYs.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-DIMhuuv0.js → DesktopAnalyticsPage-CR-m97Ui.js} +1 -1
- package/client/dist/assets/DocsDialog-CEmZp_8V.js +11 -0
- package/client/dist/assets/DocsPage-DYbAQ1AT.js +11 -0
- package/client/dist/assets/{ExportDropdown-2XwQ08sz.js → ExportDropdown-C-o1Q4ef.js} +1 -1
- package/client/dist/assets/IntegrationsPage-C6fKdwVH.js +3 -0
- package/client/dist/assets/JobDetailPage-CKfIfBgE.js +16 -0
- package/client/dist/assets/JobsPage-nBng0riZ.js +1 -0
- package/client/dist/assets/LoopBuilderPage-Co_TYqYk.js +7 -0
- package/client/dist/assets/LoopsPage-a2hd37Ya.js +1 -0
- package/client/dist/assets/{activity-Ca2XoBi-.js → activity-D8vQJrpW.js} +1 -1
- package/client/dist/assets/{addon-image-bPlduuUZ.js → addon-image-Ba-TY3wr.js} +1 -1
- package/client/dist/assets/{addon-ligatures-BexpF7xb.js → addon-ligatures-T4ARLiuu.js} +1 -1
- package/client/dist/assets/{addon-webgl-Zy4IOieH.js → addon-webgl-Cd73n8eh.js} +1 -1
- package/client/dist/assets/{addspec-DE_VfIyP.js → addspec-BloGn_ey.js} +1 -1
- package/client/dist/assets/agent-9WdSxPU5.js +1 -0
- package/client/dist/assets/agent-ASIyVcg0.js +1 -0
- package/client/dist/assets/agent-Bm2tPrdr.js +1 -0
- package/client/dist/assets/agent-C4bO1l_v.js +1 -0
- package/client/dist/assets/agent-CgKsh88Z2.js +1 -0
- package/client/dist/assets/agent-DMUrz9ZS2.js +1 -0
- package/client/dist/assets/agent-Dwkz5mPS.js +1 -0
- package/client/dist/assets/agent-pO8x4jbR.js +1 -0
- package/client/dist/assets/{agents-DzhSlNZd.js → agents-BjT_xLjv.js} +1 -1
- package/client/dist/assets/{agentstudio-DCTpIqOx.js → agentstudio-CZm2rOzt.js} +1 -1
- package/client/dist/assets/{aiedit-Dirqf3Bm.js → aiedit-DYtnZU9H.js} +1 -1
- package/client/dist/assets/{analytics-BE49LbUk.js → analytics-B4FJ_pry.js} +1 -1
- package/client/dist/assets/{attachments-C2JPppoP.js → attachments-Ci6_42Kh.js} +1 -1
- package/client/dist/assets/{browser-Dpo_ug4c.js → browser-ZB1afzjZ.js} +1 -1
- package/client/dist/assets/{chat-mq1x9cxZ.js → chat-VMflhzxn.js} +1 -1
- package/client/dist/assets/chunk-BNv3lrIs.js +1 -0
- package/client/dist/assets/{code-DtIatVES.js → code-wtcs0ivb.js} +1 -1
- package/client/dist/assets/commands-Bc8y9eNo2.js +1 -0
- package/client/dist/assets/commands-Bl3-KVfj.js +1 -0
- package/client/dist/assets/commands-C5WQ9blx2.js +1 -0
- package/client/dist/assets/commands-CM99Upsz2.js +1 -0
- package/client/dist/assets/commands-Cc2WpuXa.js +1 -0
- package/client/dist/assets/commands-CckaBWdV.js +1 -0
- package/client/dist/assets/commands-DASXJD-l.js +1 -0
- package/client/dist/assets/commands-k9wbNYoi.js +1 -0
- package/client/dist/assets/{common-kftoE0Q-.js → common-BPQQkgJZ.js} +1 -1
- package/client/dist/assets/{cssMode-BijCvCxs.js → cssMode-DsArsSCT.js} +1 -1
- package/client/dist/assets/{dashboard-BQ3Oa8CE.js → dashboard-Cyzp4ox9.js} +1 -1
- package/client/dist/assets/{dist-js-D7m9--SN.js → dist-js-BHhtSerX.js} +1 -1
- package/client/dist/assets/{dist-js-nZhsq1qo.js → dist-js-CUegfF6k.js} +1 -1
- package/client/dist/assets/{editor.api2-CrNrMVfe.js → editor.api2-T7u8kQWG.js} +1 -1
- package/client/dist/assets/{editor.main-DMIcqwXb.js → editor.main-G3Sl9C67.js} +2 -2
- package/client/dist/assets/{explore-CBYU76JD.js → explore-BKVV5JSu.js} +1 -1
- package/client/dist/assets/{freemarker2-CP2AizpZ.js → freemarker2-pBzQNgFi.js} +1 -1
- package/client/dist/assets/{handlebars-8ElanPOm.js → handlebars-CtBTCnBI.js} +1 -1
- package/client/dist/assets/{html-Mu3b73tG.js → html-Dx3DYBzY.js} +1 -1
- package/client/dist/assets/{htmlMode-tHprGCEv.js → htmlMode-In7frFOo.js} +1 -1
- package/client/dist/assets/index-B0FxQALR.css +2 -0
- package/client/dist/assets/index-B7vB20Jw.js +152 -0
- package/client/dist/assets/{integrations-jJGaKwff.js → integrations-CuWnMR5L.js} +1 -1
- package/client/dist/assets/{javascript-DlG0apUe.js → javascript-BKcn-YkN.js} +1 -1
- package/client/dist/assets/{jira-BwACz875.js → jira-DXMoAKWD.js} +1 -1
- package/client/dist/assets/{jobs-DRInW0AE.js → jobs---dwa4Nf.js} +1 -1
- package/client/dist/assets/{jsonMode-Cr0T4SXO.js → jsonMode-jNREoQ3C.js} +1 -1
- package/client/dist/assets/{lib-Bu76JzdB.js → lib-PQoHlR5u.js} +1 -1
- package/client/dist/assets/{liquid-QgTgbClC.js → liquid-CtRkGqBu.js} +1 -1
- package/client/dist/assets/{loops-DfGadne0.js → loops-D8Iu6Jss.js} +1 -1
- package/client/dist/assets/{lspLanguageFeatures-D-BxkRza.js → lspLanguageFeatures-Cl3gvD_W.js} +1 -1
- package/client/dist/assets/{mcp-D-zQCO5E.js → mcp-CIH0pH1K.js} +1 -1
- package/client/dist/assets/{mdx-B2QTaeRe.js → mdx-B_nJldHz.js} +1 -1
- package/client/dist/assets/{monaco.contribution-CkdGfXCC.js → monaco.contribution-PUeaZk8T.js} +2 -2
- package/client/dist/assets/{nav-CyHKTZxn.js → nav-DE3yWQw6.js} +1 -1
- package/client/dist/assets/{python-BlF0qnMQ.js → python-DS1Ce-A6.js} +1 -1
- package/client/dist/assets/{razor--3PSy3lb.js → razor-L41Qg9OK.js} +1 -1
- package/client/dist/assets/settings-BKmORxlB2.js +1 -0
- package/client/dist/assets/settings-BVv2JgQ8.js +1 -0
- package/client/dist/assets/settings-Bghm3pAV.js +1 -0
- package/client/dist/assets/settings-BuC_aplX.js +1 -0
- package/client/dist/assets/settings-Bw_Qk8E32.js +1 -0
- package/client/dist/assets/settings-CAKgJv7p.js +1 -0
- package/client/dist/assets/settings-CEUgk1Ck.js +1 -0
- package/client/dist/assets/settings-C_PDE20s2.js +1 -0
- package/client/dist/assets/setup-4us-Bz3H.js +1 -0
- package/client/dist/assets/setup-BYoDYoPY2.js +1 -0
- package/client/dist/assets/setup-Bf9eLKxU.js +1 -0
- package/client/dist/assets/setup-C5UbM0RP.js +1 -0
- package/client/dist/assets/setup-CqGrWb6G.js +1 -0
- package/client/dist/assets/setup-JFkWWZnR.js +1 -0
- package/client/dist/assets/setup-faMApo0U2.js +1 -0
- package/client/dist/assets/setup-tloaTobG2.js +1 -0
- package/client/dist/assets/{specs-Dslng_yW.js → specs-BYeAbIEy.js} +1 -1
- package/client/dist/assets/{terminal-XciDq6VV.js → terminal-DFPNRLKp.js} +1 -1
- package/client/dist/assets/{tickets-DbcMWq5L.js → tickets-CkfbISuK.js} +1 -1
- package/client/dist/assets/{tsMode-CHfsvcOI.js → tsMode-BC1g186U.js} +1 -1
- package/client/dist/assets/{typescript-Bjxf6BOp.js → typescript-BGlRGvJW.js} +1 -1
- package/client/dist/assets/upload-PnJDPHZH.js +1 -0
- package/client/dist/assets/{value-fEDhg5Bd.js → value-BTDefcOV.js} +1 -1
- package/client/dist/assets/{workers-CAAvSda9.js → workers-CXcXtO3b.js} +1 -1
- package/client/dist/assets/{xml-iYCSJ4oL.js → xml-JdZZaIhJ.js} +1 -1
- package/client/dist/assets/{yaml-DtO-_yDY.js → yaml-Cm82BVBt.js} +1 -1
- package/client/dist/index.html +30 -29
- package/docs/guide/de/integrations/6-agent-chat.md +64 -0
- package/docs/guide/en/integrations/6-agent-chat.md +64 -0
- package/docs/guide/es/integrations/6-agent-chat.md +64 -0
- package/docs/guide/fr/integrations/6-agent-chat.md +64 -0
- package/docs/guide/it/integrations/6-agent-chat.md +64 -0
- package/docs/guide/ja/integrations/6-agent-chat.md +64 -0
- package/docs/guide/pt/integrations/6-agent-chat.md +64 -0
- package/docs/guide/zh/integrations/6-agent-chat.md +64 -0
- package/package.json +1 -1
- package/server/dist/agent-chat-manager.js +224 -0
- package/server/dist/agent-chat-router.js +148 -0
- package/server/dist/agent-cwd-manager.js +94 -0
- package/server/dist/agent-mcp-config.js +208 -0
- package/server/dist/agent-store.js +59 -0
- package/server/dist/agent-tier.js +86 -0
- package/server/dist/desktop-db.js +27 -0
- package/server/dist/index.js +8 -0
- package/server/dist/mcp/tools/setup.js +30 -50
- package/server/dist/mcp/tools/types.js +21 -2
- package/server/dist/project-router-setup.js +15 -1
- package/server/dist/providers/codex-adapter.js +19 -3
- package/server/dist/setup-manager.js +28 -0
- package/server/dist/spawn-lifecycle.js +21 -13
- package/server/dist/workspace-manager.js +11 -0
- package/client/dist/assets/AgentsPage-CFaIiyAA.js +0 -86
- package/client/dist/assets/AnalyticsPage-DY8ECq2R.js +0 -1
- package/client/dist/assets/CodePage-DAFtRafz.js +0 -2
- package/client/dist/assets/DocsDialog-DBYhv3SM.js +0 -11
- package/client/dist/assets/DocsPage-DeLRn8W_.js +0 -11
- package/client/dist/assets/IntegrationsPage-DB-a4FDV.js +0 -3
- package/client/dist/assets/JobDetailPage-C3lljMiV.js +0 -16
- package/client/dist/assets/JobsPage-CzquwJ6G.js +0 -1
- package/client/dist/assets/LoopBuilderPage-TkoalfW5.js +0 -7
- package/client/dist/assets/LoopsPage-ypooVAQ5.js +0 -1
- package/client/dist/assets/chunk-CilyBKbf.js +0 -1
- package/client/dist/assets/commands-CwypztRT.js +0 -1
- package/client/dist/assets/commands-CxReviyc.js +0 -1
- package/client/dist/assets/commands-CzP1qQyD.js +0 -1
- package/client/dist/assets/commands-DGP46UxM.js +0 -1
- package/client/dist/assets/commands-DQvoMqa7.js +0 -1
- package/client/dist/assets/commands-DeKaz04Q.js +0 -1
- package/client/dist/assets/commands-DwYhwQsF.js +0 -1
- package/client/dist/assets/commands-lm6Vlght.js +0 -1
- package/client/dist/assets/index-BRMyOS1B.css +0 -2
- package/client/dist/assets/index-CDEQ4aU_.js +0 -144
- package/client/dist/assets/settings-BN4dufu6.js +0 -1
- package/client/dist/assets/settings-Bap_q3rt.js +0 -1
- package/client/dist/assets/settings-BlYjWMy5.js +0 -1
- package/client/dist/assets/settings-C7t_uUz4.js +0 -1
- package/client/dist/assets/settings-CIFrUsKt.js +0 -1
- package/client/dist/assets/settings-Cbj9VWmI.js +0 -1
- package/client/dist/assets/settings-D7saHMU8.js +0 -1
- package/client/dist/assets/settings-DrRjM5e8.js +0 -1
- package/client/dist/assets/setup-BiQ7ut8d.js +0 -1
- package/client/dist/assets/setup-BxvjG5Xp.js +0 -1
- package/client/dist/assets/setup-CQ-F6Ciq.js +0 -1
- package/client/dist/assets/setup-D2JlpJEz.js +0 -1
- package/client/dist/assets/setup-DG1R6J6o.js +0 -1
- package/client/dist/assets/setup-DuFJZJsm.js +0 -1
- package/client/dist/assets/setup-DyJszDqm.js +0 -1
- package/client/dist/assets/setup-Ynw19V8w.js +0 -1
- package/client/dist/assets/upload-x42OZJr2.js +0 -1
- /package/client/dist/assets/{abap-BFJA_Joo.js → abap-CpHUwCVK.js} +0 -0
- /package/client/dist/assets/{activity-oLgwaVyt.js → activity-B82z3Pna.js} +0 -0
- /package/client/dist/assets/{activity-D62CDlQz.js → activity-BId0pwuS2.js} +0 -0
- /package/client/dist/assets/{activity-BXBMi28x.js → activity-BVpZrs0J.js} +0 -0
- /package/client/dist/assets/{activity-DAFuSwnt.js → activity-BySXFT2J2.js} +0 -0
- /package/client/dist/assets/{activity-By6I70Ws.js → activity-DIWnV0Pl.js} +0 -0
- /package/client/dist/assets/{activity-Did0FnrH.js → activity-Uj576ckT.js} +0 -0
- /package/client/dist/assets/{activity-CfedQaof.js → activity-w1qMFwxh.js} +0 -0
- /package/client/dist/assets/{addspec-Cvm06hGe.js → addspec-B9dY_F5T.js} +0 -0
- /package/client/dist/assets/{addspec-gthH-H1g.js → addspec-B9nhMikb.js} +0 -0
- /package/client/dist/assets/{addspec-DwoLTocx.js → addspec-BtNaJHu2.js} +0 -0
- /package/client/dist/assets/{addspec-B2fTENuq.js → addspec-D43TlMVp2.js} +0 -0
- /package/client/dist/assets/{addspec-CFsLeQKV.js → addspec-DfgIZ5lO.js} +0 -0
- /package/client/dist/assets/{addspec-CkHI5c5H.js → addspec-W0r16BOC2.js} +0 -0
- /package/client/dist/assets/{addspec-BmggyuCD.js → addspec-tbxr3sHa.js} +0 -0
- /package/client/dist/assets/{agents-B-rVIhuw.js → agents-52t8NVpS.js} +0 -0
- /package/client/dist/assets/{agents-CZQvKDIb.js → agents-BAxAwHy-.js} +0 -0
- /package/client/dist/assets/{agents-D7nWnLg6.js → agents-BUYBb825.js} +0 -0
- /package/client/dist/assets/{agents-CuRY-Zg_.js → agents-C07al8rI.js} +0 -0
- /package/client/dist/assets/{agents-E-42N3b1.js → agents-DfGvYtpq2.js} +0 -0
- /package/client/dist/assets/{agents-4fnKlwcG.js → agents-Dli56gr82.js} +0 -0
- /package/client/dist/assets/{agents-BRUz6RJs.js → agents-Eqw_AQ6H.js} +0 -0
- /package/client/dist/assets/{agentstudio-Dq-bZrI3.js → agentstudio-0o3XKrcy.js} +0 -0
- /package/client/dist/assets/{agentstudio-CIe9C892.js → agentstudio-Bu8m5jDw.js} +0 -0
- /package/client/dist/assets/{agentstudio-D0bQBWpI.js → agentstudio-C7xxqVWn.js} +0 -0
- /package/client/dist/assets/{agentstudio-n0pmwz2I.js → agentstudio-D-UoNAIA.js} +0 -0
- /package/client/dist/assets/{agentstudio-CYGk-jjo.js → agentstudio-OJjjz6Uf2.js} +0 -0
- /package/client/dist/assets/{agentstudio-BtASTJl7.js → agentstudio-ObTpVbBP.js} +0 -0
- /package/client/dist/assets/{agentstudio-CwiS3BTp.js → agentstudio-PzFB3vfh2.js} +0 -0
- /package/client/dist/assets/{aiedit-s1T1EMK8.js → aiedit-BIQqv2XM2.js} +0 -0
- /package/client/dist/assets/{aiedit-CunYxmW0.js → aiedit-BaLZalLa.js} +0 -0
- /package/client/dist/assets/{aiedit-CZBZAyeK.js → aiedit-BjlUzasF.js} +0 -0
- /package/client/dist/assets/{aiedit-uIDh2tlc.js → aiedit-BmDufyGU.js} +0 -0
- /package/client/dist/assets/{aiedit-1Z-UYKFb.js → aiedit-DAM_WRAl2.js} +0 -0
- /package/client/dist/assets/{aiedit-CYnsp1Iv.js → aiedit-DRrNiaB4.js} +0 -0
- /package/client/dist/assets/{aiedit-BAJM9Cch.js → aiedit-sP_iao2j.js} +0 -0
- /package/client/dist/assets/{analytics-DPIkvuTS.js → analytics-BDqqCzN9.js} +0 -0
- /package/client/dist/assets/{analytics-DVFNjjAv.js → analytics-B_rxNC9X.js} +0 -0
- /package/client/dist/assets/{analytics-DRexho82.js → analytics-C4z_NgJZ.js} +0 -0
- /package/client/dist/assets/{analytics-DPmCEzvJ.js → analytics-DL2vJCbq.js} +0 -0
- /package/client/dist/assets/{analytics-g9ASAR_r.js → analytics-Ds_PNxtO2.js} +0 -0
- /package/client/dist/assets/{analytics-DZKGAUdm.js → analytics-MVJRjcY52.js} +0 -0
- /package/client/dist/assets/{analytics-B95FiMuD.js → analytics-e1mkNTgy2.js} +0 -0
- /package/client/dist/assets/{apex-C1f-z6NO.js → apex-DlD7oJX6.js} +0 -0
- /package/client/dist/assets/{atom-one-dark-CT4DolNR.js → atom-one-dark-BrRN8wBy.js} +0 -0
- /package/client/dist/assets/{attachments-Bj3HHTXV.js → attachments-8QCKHCEF2.js} +0 -0
- /package/client/dist/assets/{attachments-FFb2xHc_.js → attachments-BP0Ac1yt.js} +0 -0
- /package/client/dist/assets/{attachments-CnPS8YWu.js → attachments-CJaO1vCH.js} +0 -0
- /package/client/dist/assets/{attachments-C3skjFyH.js → attachments-CPBVeHX72.js} +0 -0
- /package/client/dist/assets/{attachments--jr2QLGv.js → attachments-CV2uaTGE.js} +0 -0
- /package/client/dist/assets/{attachments-DejzxE0C.js → attachments-CaOjdN332.js} +0 -0
- /package/client/dist/assets/{attachments-BgqfeoOx.js → attachments-Db7JfA8a.js} +0 -0
- /package/client/dist/assets/{azcli-Dr0WBJTP.js → azcli-CmXFAbc-.js} +0 -0
- /package/client/dist/assets/{bat-BKG3k49W.js → bat-DdNJq4hH.js} +0 -0
- /package/client/dist/assets/{bicep-DXs2wTcS.js → bicep-Bppz7WOA.js} +0 -0
- /package/client/dist/assets/{browser-DS6xnywt.js → browser-0xeW8fUa2.js} +0 -0
- /package/client/dist/assets/{browser-Dm_Of27q.js → browser-543jbxE4.js} +0 -0
- /package/client/dist/assets/{browser-Dm6F9bqQ.js → browser-C9rUUxo4.js} +0 -0
- /package/client/dist/assets/{browser-BS9t1qMc.js → browser-CEqx11iy.js} +0 -0
- /package/client/dist/assets/{browser-BpMo-amf.js → browser-CLC0etB_2.js} +0 -0
- /package/client/dist/assets/{browser-CsC3NOZ-.js → browser-DyG2l9Wa.js} +0 -0
- /package/client/dist/assets/{browser-U3iouSXn.js → browser-ExmELH702.js} +0 -0
- /package/client/dist/assets/{cameligo-Detknuxp.js → cameligo-0MRMdSmg.js} +0 -0
- /package/client/dist/assets/{chat-DyTbH-0F.js → chat-CCytD3P8.js} +0 -0
- /package/client/dist/assets/{chat-D78VMi-v.js → chat-CN8BMAMc.js} +0 -0
- /package/client/dist/assets/{chat-De1RgOXU.js → chat-Cu6F3d6g2.js} +0 -0
- /package/client/dist/assets/{chat-Cy78lw1n.js → chat-DagUyoVA.js} +0 -0
- /package/client/dist/assets/{chat-B2tWTbZL.js → chat-IjutwlBg.js} +0 -0
- /package/client/dist/assets/{chat-sqZyn0C4.js → chat-NQPCBQo72.js} +0 -0
- /package/client/dist/assets/{chat-CXOJHDUZ.js → chat-vVpwkOp52.js} +0 -0
- /package/client/dist/assets/{clojure-CCu4UNKg.js → clojure-B5dKj863.js} +0 -0
- /package/client/dist/assets/{clsx-pVRQNNR0.js → clsx-1dnHRn8W.js} +0 -0
- /package/client/dist/assets/{code-CLTuhuvM.js → code-32l6Naxu2.js} +0 -0
- /package/client/dist/assets/{code-CwGlPuwb.js → code-BaG05zK62.js} +0 -0
- /package/client/dist/assets/{code-DFCDV5e1.js → code-C5cibF2F.js} +0 -0
- /package/client/dist/assets/{code-Do27r8WG.js → code-Ce-nBIwj.js} +0 -0
- /package/client/dist/assets/{code-Drc7f197.js → code-Dap54vOb.js} +0 -0
- /package/client/dist/assets/{code-6LokPmIE.js → code-Dhb6jbAU.js} +0 -0
- /package/client/dist/assets/{code-Djq48g0s.js → code-_NOCo-Ol2.js} +0 -0
- /package/client/dist/assets/{coffee-Bam7Y9IR.js → coffee-DSbWjzk7.js} +0 -0
- /package/client/dist/assets/{common-DH9A-wTo.js → common-0aY9HQBP.js} +0 -0
- /package/client/dist/assets/{common-C_-0fZsp.js → common-5jScBJqt.js} +0 -0
- /package/client/dist/assets/{common-SyTaRc_K.js → common-BdaRciTu.js} +0 -0
- /package/client/dist/assets/{common-B0crwfK0.js → common-CHARW6MZ2.js} +0 -0
- /package/client/dist/assets/{common-BlqmiTj4.js → common-CQCJzAQq2.js} +0 -0
- /package/client/dist/assets/{common-DJM41wFl.js → common-DNhhqjlJ.js} +0 -0
- /package/client/dist/assets/{common-CIUPtPdu.js → common-YdyZtmaI2.js} +0 -0
- /package/client/dist/assets/{cpp-BhOkAe-9.js → cpp-SBF8SAh9.js} +0 -0
- /package/client/dist/assets/{csharp-BgHArJNx.js → csharp-Lzuq_1t-.js} +0 -0
- /package/client/dist/assets/{csp-Xzh56_3-.js → csp-BEzxZqi1.js} +0 -0
- /package/client/dist/assets/{css-CD7-RYRS.js → css-C3D3PKln.js} +0 -0
- /package/client/dist/assets/{cypher-l2xAdF3X.js → cypher-CQ3dEPmv.js} +0 -0
- /package/client/dist/assets/{dart-CDOWeyzt.js → dart-DCPmxolI.js} +0 -0
- /package/client/dist/assets/{dashboard-Dxgb47lO.js → dashboard-BTiH361F.js} +0 -0
- /package/client/dist/assets/{dashboard-B1rs1wki.js → dashboard-COSm_14E.js} +0 -0
- /package/client/dist/assets/{dashboard-D9QPCmv3.js → dashboard-CfOs70FN2.js} +0 -0
- /package/client/dist/assets/{dashboard-ajT8usAi.js → dashboard-CzHDp14_2.js} +0 -0
- /package/client/dist/assets/{dashboard-TuElRCZX.js → dashboard-D6Woy2B5.js} +0 -0
- /package/client/dist/assets/{dashboard-zwN2xswo.js → dashboard-DwbH4oVH.js} +0 -0
- /package/client/dist/assets/{dashboard-UWXs9_wy.js → dashboard-cWhU3krA2.js} +0 -0
- /package/client/dist/assets/{dockerfile-Dv8atx7v.js → dockerfile-B_2_aaTO.js} +0 -0
- /package/client/dist/assets/{ecl-DIYTlbD_.js → ecl-rADUeXsV.js} +0 -0
- /package/client/dist/assets/{elixir-CR7PLJja.js → elixir-DOd-TuJO.js} +0 -0
- /package/client/dist/assets/{explore-Jkw93usp.js → explore-B82VMUJ_.js} +0 -0
- /package/client/dist/assets/{explore-CvM08PpD.js → explore-BGz1rvQE.js} +0 -0
- /package/client/dist/assets/{explore-CE0wSNV1.js → explore-BzdMEpuf.js} +0 -0
- /package/client/dist/assets/{explore-mLI5eXks.js → explore-CbW0381i2.js} +0 -0
- /package/client/dist/assets/{explore-BYFCCka4.js → explore-ChtxIiSM.js} +0 -0
- /package/client/dist/assets/{explore-kK239uoZ.js → explore-DfcUfiPw2.js} +0 -0
- /package/client/dist/assets/{explore-CSDcRUNj.js → explore-yRF7wFSp2.js} +0 -0
- /package/client/dist/assets/{flow9-DCK5-6NG.js → flow9-Bf7zg_j0.js} +0 -0
- /package/client/dist/assets/{format-command-rVyGPxWE.js → format-command-D96da4fZ.js} +0 -0
- /package/client/dist/assets/{fsharp-DJ1xiUVU.js → fsharp-BqROZjbA.js} +0 -0
- /package/client/dist/assets/{go-BEvbHcbb.js → go-oQTP5uLe.js} +0 -0
- /package/client/dist/assets/{graphql-DN1ktXnz.js → graphql-CSHfTU3q.js} +0 -0
- /package/client/dist/assets/{hcl-DJaIjIEr.js → hcl-CeG-RoFJ.js} +0 -0
- /package/client/dist/assets/{ini-PlKfLEnb.js → ini-B2Dv4ohc.js} +0 -0
- /package/client/dist/assets/{integrations-TwQV3sLw.js → integrations-B0OBPU9_.js} +0 -0
- /package/client/dist/assets/{integrations-D8M8eJH2.js → integrations-BA5pM05t.js} +0 -0
- /package/client/dist/assets/{integrations-TJuDBl-9.js → integrations-BJvrlcc7.js} +0 -0
- /package/client/dist/assets/{integrations-Bdk5dMyv.js → integrations-CPKYkG36.js} +0 -0
- /package/client/dist/assets/{integrations-B8hT0Qf_.js → integrations-CnrX7vqw2.js} +0 -0
- /package/client/dist/assets/{integrations-Cj_BsXxJ.js → integrations-DBou159M2.js} +0 -0
- /package/client/dist/assets/{integrations-CYqz7YFS.js → integrations-DeJFRyXz2.js} +0 -0
- /package/client/dist/assets/{java-3PUwMlx-.js → java-aUDDeufb.js} +0 -0
- /package/client/dist/assets/{jira-DHFnvEm8.js → jira-BDgxAFTF2.js} +0 -0
- /package/client/dist/assets/{jira-NhkbrDXe.js → jira-BwLBgmfI2.js} +0 -0
- /package/client/dist/assets/{jira-wiIvGma5.js → jira-D3GGzXOI.js} +0 -0
- /package/client/dist/assets/{jira-C95FN3yk.js → jira-DeotPx6P2.js} +0 -0
- /package/client/dist/assets/{jira-CNUUgTs4.js → jira-NwlUCcQD.js} +0 -0
- /package/client/dist/assets/{jira-BoRyckbb.js → jira-Srx2P5zS.js} +0 -0
- /package/client/dist/assets/{jira--rI5PfuE.js → jira-mi37H4Kt.js} +0 -0
- /package/client/dist/assets/{jobs-Bjt5PyVv.js → jobs-B56vQEkh2.js} +0 -0
- /package/client/dist/assets/{jobs-D2QVTPbz.js → jobs-BYIk6Tg_.js} +0 -0
- /package/client/dist/assets/{jobs-LK1ImiDH.js → jobs-C-lM-iax2.js} +0 -0
- /package/client/dist/assets/{jobs-BmTs4Bn3.js → jobs-CYdevGgT.js} +0 -0
- /package/client/dist/assets/{jobs-yPz4Dvi-.js → jobs-D8adm2BX.js} +0 -0
- /package/client/dist/assets/{jobs-Cchy-18B.js → jobs-K_Y8KAZ2.js} +0 -0
- /package/client/dist/assets/{jobs-Bjp7v9aA.js → jobs-OwM0ZWhI2.js} +0 -0
- /package/client/dist/assets/{julia-DC6LnY15.js → julia-C5LbruO5.js} +0 -0
- /package/client/dist/assets/{kotlin-CoGntbZF.js → kotlin-C6mOuSKk.js} +0 -0
- /package/client/dist/assets/{less-DCFflTXL.js → less-D5qC3caW.js} +0 -0
- /package/client/dist/assets/{lexon-BTOivnjP.js → lexon-Dr2La-fj.js} +0 -0
- /package/client/dist/assets/{loops-C3OaXou9.js → loops-BDhEfnx82.js} +0 -0
- /package/client/dist/assets/{loops-Cv6Aeszq.js → loops-BM5QggwH.js} +0 -0
- /package/client/dist/assets/{loops-BU314kSd.js → loops-CPjLAAxj.js} +0 -0
- /package/client/dist/assets/{loops-LqZ4MC6J.js → loops-DKnk79TB2.js} +0 -0
- /package/client/dist/assets/{loops-SbkOdciY.js → loops-DLW0aFMm.js} +0 -0
- /package/client/dist/assets/{loops-BFIcYvpy.js → loops-Dcv3dFy_2.js} +0 -0
- /package/client/dist/assets/{loops-IQe23ef6.js → loops-y7wFRx6M.js} +0 -0
- /package/client/dist/assets/{lua-ClKCZMmP.js → lua-Zy6u5z6Z.js} +0 -0
- /package/client/dist/assets/{m3-25hKFWMb.js → m3-C7XHeDz_.js} +0 -0
- /package/client/dist/assets/{markdown-BGAj9q0K.js → markdown-PiF7r-2h.js} +0 -0
- /package/client/dist/assets/{mcp-DyERgHA2.js → mcp-B4irfLJ2.js} +0 -0
- /package/client/dist/assets/{mcp-BSCAtU6Y.js → mcp-B6nwJJmR.js} +0 -0
- /package/client/dist/assets/{mcp-DFG9OEXM.js → mcp-BOoEGTSQ.js} +0 -0
- /package/client/dist/assets/{mcp-Cb6fUaFJ.js → mcp-BP7PpbDr2.js} +0 -0
- /package/client/dist/assets/{mcp-CyP0quZ7.js → mcp-CNgFiTEh.js} +0 -0
- /package/client/dist/assets/{mcp-DCTNWpfB.js → mcp-D3E4_Mmk2.js} +0 -0
- /package/client/dist/assets/{mcp-DEFGJ1OJ.js → mcp-mupPuPDO2.js} +0 -0
- /package/client/dist/assets/{mips-BrVgY2Pf.js → mips-nn07GiyE.js} +0 -0
- /package/client/dist/assets/{msdax-7EhcRsm8.js → msdax-DaKFVMST.js} +0 -0
- /package/client/dist/assets/{mysql-B5_atCBH.js → mysql-C6d6xrbU.js} +0 -0
- /package/client/dist/assets/{nav-Br2AivTc.js → nav-1hj2izqB2.js} +0 -0
- /package/client/dist/assets/{nav-CFofO7QO.js → nav-BBUKMAu-2.js} +0 -0
- /package/client/dist/assets/{nav-_-siCrRv.js → nav-CLqkP-26.js} +0 -0
- /package/client/dist/assets/{nav-zyBhf29M.js → nav-Cv46L837.js} +0 -0
- /package/client/dist/assets/{nav-rO4Nqnh-.js → nav-DgA-rjLk2.js} +0 -0
- /package/client/dist/assets/{nav-DqyLGJmF.js → nav-EG2pr6vN.js} +0 -0
- /package/client/dist/assets/{nav-B2Cv1vjz.js → nav-r3mIJVfU.js} +0 -0
- /package/client/dist/assets/{objective-c-CLUvUl9T.js → objective-c-B6KMtI-k.js} +0 -0
- /package/client/dist/assets/{pascal-BnU1HU42.js → pascal-DYr8MPE7.js} +0 -0
- /package/client/dist/assets/{pascaligo-dsKvjFzi.js → pascaligo-B3pd-jJ_.js} +0 -0
- /package/client/dist/assets/{perl-CZne1GYG.js → perl-z2xUzoaL.js} +0 -0
- /package/client/dist/assets/{pgsql-CMa5W_iF.js → pgsql-DUvT-09-.js} +0 -0
- /package/client/dist/assets/{php-Cu4mS35J.js → php-CGyOmJfy.js} +0 -0
- /package/client/dist/assets/{pla-B7COwnnm.js → pla-CMqgvyD0.js} +0 -0
- /package/client/dist/assets/{postiats-GLeNtnBQ.js → postiats-Dx5LUn4Z.js} +0 -0
- /package/client/dist/assets/{powerquery-BqPf3R1W.js → powerquery-DazYxvJ6.js} +0 -0
- /package/client/dist/assets/{powershell-D9btb5su.js → powershell-B3nwlDka.js} +0 -0
- /package/client/dist/assets/{protobuf-6GHSuaNm.js → protobuf-BGuu2u2s.js} +0 -0
- /package/client/dist/assets/{pug-ct6rYKQd.js → pug-Dbte1MXA.js} +0 -0
- /package/client/dist/assets/{qsharp-CIrAQNPy.js → qsharp-DJLwBOvG.js} +0 -0
- /package/client/dist/assets/{r-Bk-a0sON.js → r-DmGBRSHj.js} +0 -0
- /package/client/dist/assets/{redis-C9yfaWYh.js → redis-VvUYn0a4.js} +0 -0
- /package/client/dist/assets/{redshift-DaOT1jRU.js → redshift-6GdDrxg3.js} +0 -0
- /package/client/dist/assets/{restructuredtext-C1t9LQfS.js → restructuredtext-CfAB8aRU.js} +0 -0
- /package/client/dist/assets/{ruby-COiPZJjc.js → ruby-CIYK6MXY.js} +0 -0
- /package/client/dist/assets/{rust--gZOJZzj.js → rust-CTHZfjj9.js} +0 -0
- /package/client/dist/assets/{sb-NHf3iazF.js → sb-CkKTdkz_.js} +0 -0
- /package/client/dist/assets/{scala-D1nO1TBd.js → scala-Bx-Wr9TM.js} +0 -0
- /package/client/dist/assets/{scheme-Bref42s5.js → scheme-Dcfi6f83.js} +0 -0
- /package/client/dist/assets/{scss-BS9CCLr3.js → scss-ByL-7PFQ.js} +0 -0
- /package/client/dist/assets/{shell-DT3joMBB.js → shell-Csnb9Yqd.js} +0 -0
- /package/client/dist/assets/{solidity-o2Fm9dvg.js → solidity-Dbw5-0QP.js} +0 -0
- /package/client/dist/assets/{sophia-Dj1N6Xqb.js → sophia-ZQ3saZQx.js} +0 -0
- /package/client/dist/assets/{sparql-D2fjpTWm.js → sparql-BEtOel8u.js} +0 -0
- /package/client/dist/assets/{specs-CYA5Bv7Q.js → specs-B5XOoH-02.js} +0 -0
- /package/client/dist/assets/{specs-DFCFg51O.js → specs-B8mwScoM2.js} +0 -0
- /package/client/dist/assets/{specs-DzlROLy7.js → specs-Bj_3fDrQ.js} +0 -0
- /package/client/dist/assets/{specs-CCXV-eSF.js → specs-CWNKAScX2.js} +0 -0
- /package/client/dist/assets/{specs-C-WXGBqy.js → specs-D4z5d8uq.js} +0 -0
- /package/client/dist/assets/{specs-C57koADY.js → specs-DgvIRZtM.js} +0 -0
- /package/client/dist/assets/{specs-DwRPiJTc.js → specs-DuRzE5wE.js} +0 -0
- /package/client/dist/assets/{sql-BArhsPUz.js → sql-DGPDbzB7.js} +0 -0
- /package/client/dist/assets/{st-Bd2-tALj.js → st-GeW2MOgh.js} +0 -0
- /package/client/dist/assets/{swift-DvEpXBKj.js → swift-BVYTN8jq.js} +0 -0
- /package/client/dist/assets/{systemverilog-mHEbsnVH.js → systemverilog-Deg2a8Lr.js} +0 -0
- /package/client/dist/assets/{tcl-DePutp1e.js → tcl-6DnLmROF.js} +0 -0
- /package/client/dist/assets/{terminal-CnObBCAh.js → terminal-B2sExUis.js} +0 -0
- /package/client/dist/assets/{terminal-BRQMrU74.js → terminal-CH0fdHvP.js} +0 -0
- /package/client/dist/assets/{terminal-BTiemy98.js → terminal-CPMigUX7.js} +0 -0
- /package/client/dist/assets/{terminal-2S-Wsk6L.js → terminal-DOwfkxqa2.js} +0 -0
- /package/client/dist/assets/{terminal-DcPKgKMN.js → terminal-DjSSa5qP.js} +0 -0
- /package/client/dist/assets/{terminal-CmP5riTU.js → terminal-DoMTHedv2.js} +0 -0
- /package/client/dist/assets/{terminal-CjQeWfpp.js → terminal-w0i-OCp32.js} +0 -0
- /package/client/dist/assets/{tickets-D75vyZJj.js → tickets-CQTana1u.js} +0 -0
- /package/client/dist/assets/{tickets-CcTcvwKS.js → tickets-D00mSt832.js} +0 -0
- /package/client/dist/assets/{tickets-BSyaZI8d.js → tickets-D7CSuWjO.js} +0 -0
- /package/client/dist/assets/{tickets-7kl_0jgM.js → tickets-Dq7HDy8n.js} +0 -0
- /package/client/dist/assets/{tickets-D79ZT2SZ.js → tickets-DvbFg_-c2.js} +0 -0
- /package/client/dist/assets/{tickets-mxd23fWX.js → tickets-heDAaj8C2.js} +0 -0
- /package/client/dist/assets/{tickets-ZA_2iPd1.js → tickets-onKZz6Dd.js} +0 -0
- /package/client/dist/assets/{twig-DQ2zIX0b.js → twig-XbbXW9Yz.js} +0 -0
- /package/client/dist/assets/{typespec-DPoaiGTJ.js → typespec-CRlV8GhI.js} +0 -0
- /package/client/dist/assets/{vb-Jo98wdMr.js → vb-BHE2izPH.js} +0 -0
- /package/client/dist/assets/{wgsl-DZc4h_eS.js → wgsl-Bf5vkfmY.js} +0 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveBridgeScript = resolveBridgeScript;
|
|
7
|
+
exports.resolveNodeCommand = resolveNodeCommand;
|
|
8
|
+
exports.buildSpecrailsMcpEntry = buildSpecrailsMcpEntry;
|
|
9
|
+
exports.mergeSpecrailsIntoWorkspaceMcp = mergeSpecrailsIntoWorkspaceMcp;
|
|
10
|
+
exports.buildAgentMcpArgs = buildAgentMcpArgs;
|
|
11
|
+
exports.prepareAgentMcp = prepareAgentMcp;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const os_1 = __importDefault(require("os"));
|
|
15
|
+
const path_resolver_1 = require("./path-resolver");
|
|
16
|
+
const agent_tier_1 = require("./agent-tier");
|
|
17
|
+
// ─── Agent MCP wiring (design D8 / D1) ────────────────────────────────────────
|
|
18
|
+
//
|
|
19
|
+
// The in-app agent drives the app by talking to its OWN embedded MCP server. We
|
|
20
|
+
// spawn the AI CLI with `--mcp-config` pointing at a generated config whose sole
|
|
21
|
+
// server is the bundled `specrails-mcp` stdio bridge, which relays to
|
|
22
|
+
// `127.0.0.1:<port>/api/mcp` and reads the scoped token from disk (no token is
|
|
23
|
+
// ever written into the config file). The current Shift+Tab ladder level is
|
|
24
|
+
// forwarded via env → the bridge sets it as a loopback-only header so the tool
|
|
25
|
+
// guard enforces the agent ladder independently of the external Settings tiers.
|
|
26
|
+
function homeDir() {
|
|
27
|
+
return process.env.SPECRAILS_REGISTRY_HOME || os_1.default.homedir();
|
|
28
|
+
}
|
|
29
|
+
function fileExists(p) {
|
|
30
|
+
try {
|
|
31
|
+
return fs_1.default.existsSync(p);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Absolute path to the `specrails-mcp` bridge JS. Resolution order:
|
|
39
|
+
* 1. SPECRAILS_BUNDLED_MCP_BRIDGE_PATH (set by the Tauri host in the packaged app)
|
|
40
|
+
* 2. the staged copy under src-tauri/binaries/ (dev + bundled layouts)
|
|
41
|
+
* 3. the mcp-bridge build output (mcp-bridge/dist/)
|
|
42
|
+
* Climbs from this module so it works whether running from server/ or server/dist/.
|
|
43
|
+
*/
|
|
44
|
+
function resolveBridgeScript() {
|
|
45
|
+
const fromEnv = process.env.SPECRAILS_BUNDLED_MCP_BRIDGE_PATH;
|
|
46
|
+
if (fromEnv && fileExists(fromEnv))
|
|
47
|
+
return fromEnv;
|
|
48
|
+
const roots = [
|
|
49
|
+
path_1.default.resolve(__dirname, '..'),
|
|
50
|
+
path_1.default.resolve(__dirname, '..', '..'),
|
|
51
|
+
process.cwd(),
|
|
52
|
+
];
|
|
53
|
+
const rels = [
|
|
54
|
+
path_1.default.join('src-tauri', 'binaries', 'specrails-mcp.js'),
|
|
55
|
+
path_1.default.join('mcp-bridge', 'dist', 'specrails-mcp.js'),
|
|
56
|
+
];
|
|
57
|
+
for (const root of roots) {
|
|
58
|
+
for (const rel of rels) {
|
|
59
|
+
const candidate = path_1.default.join(root, rel);
|
|
60
|
+
if (fileExists(candidate))
|
|
61
|
+
return candidate;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/** The node executable that should run the bridge (bundled in the packaged app, else PATH `node`). */
|
|
67
|
+
function resolveNodeCommand() {
|
|
68
|
+
return (0, path_resolver_1.resolveBundledNodeExe)() ?? 'node';
|
|
69
|
+
}
|
|
70
|
+
/** Build the `mcpServers.specrails` entry the agent (or a project workspace) uses. */
|
|
71
|
+
function buildSpecrailsMcpEntry(opts) {
|
|
72
|
+
const bridge = resolveBridgeScript();
|
|
73
|
+
if (!bridge)
|
|
74
|
+
return null;
|
|
75
|
+
const env = {
|
|
76
|
+
SPECRAILS_MCP_PORT: String(opts.port),
|
|
77
|
+
};
|
|
78
|
+
// Preserve the test-home override so the bridge reads the right token file.
|
|
79
|
+
if (process.env.SPECRAILS_REGISTRY_HOME)
|
|
80
|
+
env.SPECRAILS_REGISTRY_HOME = process.env.SPECRAILS_REGISTRY_HOME;
|
|
81
|
+
if (opts.tierLevel != null)
|
|
82
|
+
env[agent_tier_1.AGENT_TIER_ENV] = (0, agent_tier_1.tierNameForLevel)(opts.tierLevel);
|
|
83
|
+
if (opts.activeProjectId)
|
|
84
|
+
env[agent_tier_1.AGENT_PROJECT_ENV] = opts.activeProjectId;
|
|
85
|
+
return { command: resolveNodeCommand(), args: [bridge], env };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Part A (design D8): surgically merge the `specrails` MCP server into a
|
|
89
|
+
* project's app-managed WORKSPACE `.mcp.json` so the project's own rails/explore/
|
|
90
|
+
* chat spawns can also call the Specrails MCP. NEVER touches the pristine repo.
|
|
91
|
+
* Additive + idempotent: preserves any existing (e.g. plugin) mcpServers entries,
|
|
92
|
+
* writes atomically (temp + rename), inlines NO token. Returns true when written.
|
|
93
|
+
*/
|
|
94
|
+
function mergeSpecrailsIntoWorkspaceMcp(workspaceDir, port) {
|
|
95
|
+
const entry = buildSpecrailsMcpEntry({ port });
|
|
96
|
+
if (!entry)
|
|
97
|
+
return false;
|
|
98
|
+
const file = path_1.default.join(workspaceDir, '.mcp.json');
|
|
99
|
+
let current = {};
|
|
100
|
+
try {
|
|
101
|
+
if (fs_1.default.existsSync(file)) {
|
|
102
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf-8'));
|
|
103
|
+
if (parsed && typeof parsed === 'object')
|
|
104
|
+
current = parsed;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Corrupt file → start fresh rather than crash assembly.
|
|
109
|
+
current = {};
|
|
110
|
+
}
|
|
111
|
+
const mcpServers = { ...(current.mcpServers ?? {}), specrails: entry };
|
|
112
|
+
const next = { ...current, mcpServers };
|
|
113
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
114
|
+
fs_1.default.mkdirSync(workspaceDir, { recursive: true });
|
|
115
|
+
fs_1.default.writeFileSync(tmp, JSON.stringify(next, null, 2));
|
|
116
|
+
fs_1.default.renameSync(tmp, file);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Writes a per-conversation `--mcp-config` file for the agent and returns the
|
|
121
|
+
* `['--mcp-config', <file>]` argv to inject into SpawnOptions.extraArgs. Uses the
|
|
122
|
+
* bundled `specrails-mcp` stdio bridge (shipped inside the app — the user installs
|
|
123
|
+
* nothing; 100% unattended) which relays to this process's `/api/mcp`. Returns
|
|
124
|
+
* `[]` when the bridge can't be located (agent then runs tool-less / degraded).
|
|
125
|
+
*/
|
|
126
|
+
function buildAgentMcpArgs(opts) {
|
|
127
|
+
const entry = buildSpecrailsMcpEntry({ port: opts.port, tierLevel: opts.tierLevel, activeProjectId: opts.activeProjectId });
|
|
128
|
+
if (!entry)
|
|
129
|
+
return [];
|
|
130
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(opts.conversationId)) {
|
|
131
|
+
throw new Error(`unsafe agent conversation id: ${opts.conversationId}`);
|
|
132
|
+
}
|
|
133
|
+
const dir = path_1.default.join(homeDir(), '.specrails', 'agent', opts.conversationId);
|
|
134
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
135
|
+
const file = path_1.default.join(dir, 'mcp.json');
|
|
136
|
+
fs_1.default.writeFileSync(file, JSON.stringify({ mcpServers: { specrails: entry } }, null, 2), { mode: 0o600 });
|
|
137
|
+
try {
|
|
138
|
+
fs_1.default.chmodSync(file, 0o600);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* best-effort on platforms without chmod */
|
|
142
|
+
}
|
|
143
|
+
return ['--mcp-config', file];
|
|
144
|
+
}
|
|
145
|
+
function agentDir(conversationId) {
|
|
146
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(conversationId)) {
|
|
147
|
+
throw new Error(`unsafe agent conversation id: ${conversationId}`);
|
|
148
|
+
}
|
|
149
|
+
const dir = path_1.default.join(homeDir(), '.specrails', 'agent', conversationId);
|
|
150
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
151
|
+
return dir;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Codex registers the specrails MCP via inline `-c mcp_servers.specrails.*`
|
|
155
|
+
* config overrides. This keeps codex on the USER's real CODEX_HOME (auth + model
|
|
156
|
+
* settings intact — no all-or-nothing 401 from a CODEX_HOME override) and cannot
|
|
157
|
+
* break codex startup the way an unknown `--mcp-config` flag does: `-c` is a known
|
|
158
|
+
* flag and unknown config keys are simply set. TOML scalar values reuse JSON
|
|
159
|
+
* escaping (compatible for our command/path/env inputs).
|
|
160
|
+
*/
|
|
161
|
+
function codexMcpOverrides(entry) {
|
|
162
|
+
const c = (kv) => ['-c', kv];
|
|
163
|
+
const args = [
|
|
164
|
+
...c(`mcp_servers.specrails.command=${JSON.stringify(entry.command)}`),
|
|
165
|
+
...c(`mcp_servers.specrails.args=[${entry.args.map((a) => JSON.stringify(a)).join(', ')}]`),
|
|
166
|
+
];
|
|
167
|
+
for (const [k, v] of Object.entries(entry.env)) {
|
|
168
|
+
args.push(...c(`mcp_servers.specrails.env.${k}=${JSON.stringify(v)}`));
|
|
169
|
+
}
|
|
170
|
+
return args;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Prepares the specrails MCP for the given provider and returns the spawn
|
|
174
|
+
* extraArgs + env to merge. Returns empty wiring when the bridge is unavailable
|
|
175
|
+
* (agent then runs tool-less / degraded).
|
|
176
|
+
*/
|
|
177
|
+
function prepareAgentMcp(opts) {
|
|
178
|
+
const entry = buildSpecrailsMcpEntry({
|
|
179
|
+
port: opts.port,
|
|
180
|
+
tierLevel: opts.tierLevel,
|
|
181
|
+
activeProjectId: opts.activeProjectId,
|
|
182
|
+
});
|
|
183
|
+
if (!entry)
|
|
184
|
+
return { extraArgs: [], env: {} };
|
|
185
|
+
if (opts.adapterId === 'codex') {
|
|
186
|
+
// Inline -c overrides — no CODEX_HOME override, no file mutation; auth intact.
|
|
187
|
+
return { extraArgs: codexMcpOverrides(entry), env: {} };
|
|
188
|
+
}
|
|
189
|
+
if (opts.adapterId === 'claude') {
|
|
190
|
+
return { extraArgs: buildAgentMcpArgs(opts), env: {} };
|
|
191
|
+
}
|
|
192
|
+
// gemini + any other project-json provider: write .mcp.json in the spawn cwd.
|
|
193
|
+
const file = path_1.default.join(opts.cwd, '.mcp.json');
|
|
194
|
+
let current = {};
|
|
195
|
+
try {
|
|
196
|
+
if (fs_1.default.existsSync(file)) {
|
|
197
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf-8'));
|
|
198
|
+
if (parsed && typeof parsed === 'object')
|
|
199
|
+
current = parsed;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
current = {};
|
|
204
|
+
}
|
|
205
|
+
const next = { ...current, mcpServers: { ...(current.mcpServers ?? {}), specrails: entry } };
|
|
206
|
+
fs_1.default.writeFileSync(file, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
207
|
+
return { extraArgs: [], env: {} };
|
|
208
|
+
}
|
|
@@ -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;
|
package/server/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ 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
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");
|
|
27
29
|
const browser_playwright_1 = require("./browser-playwright");
|
|
28
30
|
const telemetry_receiver_1 = require("./telemetry-receiver");
|
|
29
31
|
const telemetry_compactor_1 = require("./telemetry-compactor");
|
|
@@ -235,6 +237,7 @@ let _registry = null;
|
|
|
235
237
|
/** The mobile companion gateway (off by default); torn down on shutdown. */
|
|
236
238
|
let _mobileGateway = null;
|
|
237
239
|
let _mcpManager = null;
|
|
240
|
+
let _agentChatManager = null;
|
|
238
241
|
server.on('upgrade', (request, socket, head) => {
|
|
239
242
|
const urlStr = request.url ?? '/';
|
|
240
243
|
const auth = authorizeUpgrade(request);
|
|
@@ -536,6 +539,10 @@ function applyPtyWsRateLimiting(ws) {
|
|
|
536
539
|
if (mcpManager.isEnabledSetting()) {
|
|
537
540
|
mcpManager.start().catch((err) => console.error('[mcp] boot start failed:', err));
|
|
538
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 }));
|
|
539
546
|
// App-level routes. CRITICAL mount order: the desktop router is mounted at
|
|
540
547
|
// '/api' BEFORE the project router below so its exact routes (e.g.
|
|
541
548
|
// GET /api/projects, DELETE /api/projects/:id) are handled here, while
|
|
@@ -641,6 +648,7 @@ async function shutdown() {
|
|
|
641
648
|
try {
|
|
642
649
|
await _mobileGateway?.stop();
|
|
643
650
|
await _mcpManager?.stop();
|
|
651
|
+
await _agentChatManager?.shutdown();
|
|
644
652
|
}
|
|
645
653
|
catch { /* ignore */ }
|
|
646
654
|
try {
|
|
@@ -7,20 +7,23 @@ const types_1 = require("./types");
|
|
|
7
7
|
* The setup-wizard domain facade. Mixes APP-LEVEL operations (prerequisites,
|
|
8
8
|
* available_providers, add_project — mounted at `/api` with NO `:projectId`)
|
|
9
9
|
* with PER-PROJECT operations (install-config, install, checkpoints, abort,
|
|
10
|
-
* integration-contract
|
|
10
|
+
* integration-contract — under `/api/projects/:projectId/*`).
|
|
11
|
+
*
|
|
12
|
+
* QUICK-only: the agent path provisions the quick (offline) tier and installs
|
|
13
|
+
* every registered provider in ONE `install` call (the server chains them). The
|
|
14
|
+
* legacy full/enrich AI flow is intentionally NOT exposed through the MCP.
|
|
11
15
|
*
|
|
12
16
|
* LIFECYCLE the caller must respect:
|
|
13
17
|
* 1. prerequisites → must be ok before adding a project
|
|
14
18
|
* 2. add_project → creates the ProjectContext + slug + registry mirror + workspace
|
|
15
|
-
* 3. install_config (one POST per provider for multi-provider projects)
|
|
16
|
-
* 4. install → 202 async;
|
|
19
|
+
* 3. install_config (one POST per provider for multi-provider projects; tier forced to quick)
|
|
20
|
+
* 4. install → 202 async; installs ALL providers; result arrives via WS / checkpoints
|
|
17
21
|
* 5. poll checkpoints (or stream WS) until isInstalling === false
|
|
18
|
-
* 6. optional enrich / enrich_message for the legacy full AI flow
|
|
19
22
|
*
|
|
20
|
-
* The async
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* The async `install` action returns immediately (HTTP 202) and does the real,
|
|
24
|
+
* long-running work in a detached child whose only output channel is WebSocket —
|
|
25
|
+
* so it returns a hint to poll `checkpoints` (which also exposes
|
|
26
|
+
* isInstalling/logLines/summary) for true completion.
|
|
24
27
|
*/
|
|
25
28
|
function setupTools() {
|
|
26
29
|
return [
|
|
@@ -31,15 +34,15 @@ function setupTools() {
|
|
|
31
34
|
'App-level actions ignore projectId: prerequisites (probe node/npm/npx/git + provider CLIs), ' +
|
|
32
35
|
'available_providers (which AI CLIs are detected + install tiers), add_project (register a repo path). ' +
|
|
33
36
|
'Per-project actions: install_config (persist install-config.yaml), install (spawn offline framework scaffold — async/202), ' +
|
|
34
|
-
'checkpoints (poll live setup/install
|
|
35
|
-
'abort (SIGTERM/SIGKILL the in-progress install
|
|
36
|
-
'
|
|
37
|
+
'checkpoints (poll live setup/install state — the canonical completion signal when not streaming WS), ' +
|
|
38
|
+
'abort (SIGTERM/SIGKILL the in-progress install child), integration_contract (read the ticket-provider contract). ' +
|
|
39
|
+
'Install is QUICK-only and provisions every registered provider in one shot; the legacy full/enrich AI flow is not exposed here.',
|
|
37
40
|
hintTier: 'read',
|
|
38
41
|
tier: (a) => {
|
|
39
42
|
const action = a.action;
|
|
40
43
|
if (action === 'abort')
|
|
41
44
|
return 'destructive';
|
|
42
|
-
if (action === 'install'
|
|
45
|
+
if (action === 'install')
|
|
43
46
|
return 'ai-spawn';
|
|
44
47
|
if (action === 'add_project' || action === 'install_config')
|
|
45
48
|
return 'write';
|
|
@@ -56,14 +59,12 @@ function setupTools() {
|
|
|
56
59
|
'checkpoints',
|
|
57
60
|
'abort',
|
|
58
61
|
'integration_contract',
|
|
59
|
-
'enrich',
|
|
60
|
-
'enrich_message',
|
|
61
62
|
])
|
|
62
63
|
.describe('Setup operation to perform'),
|
|
63
64
|
projectId: zod_1.z
|
|
64
65
|
.string()
|
|
65
66
|
.optional()
|
|
66
|
-
.describe('Project id for per-project actions (install_config/install/checkpoints/abort/integration_contract
|
|
67
|
+
.describe('Project id for per-project actions (install_config/install/checkpoints/abort/integration_contract). Ignored by app-level actions.'),
|
|
67
68
|
// prerequisites
|
|
68
69
|
diagnostic: zod_1.z
|
|
69
70
|
.boolean()
|
|
@@ -81,7 +82,7 @@ function setupTools() {
|
|
|
81
82
|
provider: zod_1.z
|
|
82
83
|
.string()
|
|
83
84
|
.optional()
|
|
84
|
-
.describe('add_project: legacy single primary provider; install
|
|
85
|
+
.describe('add_project: legacy single primary provider; install: which per-provider install-config to read'),
|
|
85
86
|
providers: zod_1.z
|
|
86
87
|
.array(zod_1.z.string())
|
|
87
88
|
.optional()
|
|
@@ -91,15 +92,6 @@ function setupTools() {
|
|
|
91
92
|
.record(zod_1.z.unknown())
|
|
92
93
|
.optional()
|
|
93
94
|
.describe('install_config: the install-config object to serialize (e.g. { tier:"quick", provider, agents }); required for install_config'),
|
|
94
|
-
// enrich_message
|
|
95
|
-
sessionId: zod_1.z
|
|
96
|
-
.string()
|
|
97
|
-
.optional()
|
|
98
|
-
.describe('enrich_message: the enrich session id to resume (required for enrich_message)'),
|
|
99
|
-
message: zod_1.z
|
|
100
|
-
.string()
|
|
101
|
-
.optional()
|
|
102
|
-
.describe('enrich_message: the user reply to send into the enrich session (required for enrich_message)'),
|
|
103
95
|
},
|
|
104
96
|
async handler(ctx, args) {
|
|
105
97
|
const action = args.action;
|
|
@@ -131,17 +123,27 @@ function setupTools() {
|
|
|
131
123
|
if (config === undefined || typeof config !== 'object' || Array.isArray(config)) {
|
|
132
124
|
throw new Error('install_config requires a "config" object.');
|
|
133
125
|
}
|
|
134
|
-
|
|
126
|
+
// The MCP/agent path is QUICK-only — force the tier so a full/enrich
|
|
127
|
+
// install can never be provisioned through the agent (deprecated).
|
|
128
|
+
const quickConfig = { ...config, tier: 'quick' };
|
|
129
|
+
return (0, types_1.apiCall)(ctx, 'POST', `${base}/setup/install-config`, quickConfig);
|
|
135
130
|
}
|
|
136
131
|
case 'install': {
|
|
137
132
|
const base = (0, types_1.projectPath)(ctx, args.projectId);
|
|
133
|
+
// Quick-only, all-provider install: by default provision EVERY provider
|
|
134
|
+
// the project is registered with in one shot (server chains them). An
|
|
135
|
+
// explicit `providers` list narrows it; a single `provider` still works.
|
|
138
136
|
const body = {};
|
|
139
|
-
if (
|
|
137
|
+
if (Array.isArray(args.providers))
|
|
138
|
+
body.providers = args.providers;
|
|
139
|
+
else if (typeof args.provider === 'string')
|
|
140
140
|
body.provider = args.provider;
|
|
141
|
+
else
|
|
142
|
+
body.all = true;
|
|
141
143
|
const r = await (0, types_1.apiCall)(ctx, 'POST', `${base}/setup/install`, body);
|
|
142
144
|
return {
|
|
143
145
|
...(typeof r === 'object' && r !== null ? r : { result: r }),
|
|
144
|
-
hint: 'Install is async (HTTP 202).
|
|
146
|
+
hint: 'Install is async (HTTP 202). Installs ALL registered providers (quick tier) in one shot; poll specrails_setup(checkpoints) until isInstalling === false, or stream the setup_install_done / setup_error WS events.',
|
|
145
147
|
};
|
|
146
148
|
}
|
|
147
149
|
case 'checkpoints': {
|
|
@@ -156,28 +158,6 @@ function setupTools() {
|
|
|
156
158
|
const base = (0, types_1.projectPath)(ctx, args.projectId);
|
|
157
159
|
return (0, types_1.apiCall)(ctx, 'GET', `${base}/integration-contract`);
|
|
158
160
|
}
|
|
159
|
-
case 'enrich': {
|
|
160
|
-
const base = (0, types_1.projectPath)(ctx, args.projectId);
|
|
161
|
-
const r = await (0, types_1.apiCall)(ctx, 'POST', `${base}/enrich/start`, {});
|
|
162
|
-
return {
|
|
163
|
-
...(typeof r === 'object' && r !== null ? r : { result: r }),
|
|
164
|
-
hint: 'Enrich is async (HTTP 202) and COST-INCURRING. Poll specrails_setup(checkpoints) until isEnriching === false, or stream the setup_complete / setup_turn_done / setup_error WS events. Use enrich_message to answer clarifying questions.',
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
case 'enrich_message': {
|
|
168
|
-
const base = (0, types_1.projectPath)(ctx, args.projectId);
|
|
169
|
-
const sessionId = args.sessionId;
|
|
170
|
-
const message = args.message;
|
|
171
|
-
if (!sessionId)
|
|
172
|
-
throw new Error('enrich_message requires a "sessionId".');
|
|
173
|
-
if (!message || !message.trim())
|
|
174
|
-
throw new Error('enrich_message requires a non-empty "message".');
|
|
175
|
-
const r = await (0, types_1.apiCall)(ctx, 'POST', `${base}/enrich/message`, { sessionId, message });
|
|
176
|
-
return {
|
|
177
|
-
...(typeof r === 'object' && r !== null ? r : { result: r }),
|
|
178
|
-
hint: 'Enrich-message is async (HTTP 202) and COST-INCURRING. Poll specrails_setup(checkpoints) until isEnriching === false, or stream the setup_turn_done / setup_error WS events.',
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
161
|
default:
|
|
182
162
|
throw new Error(`Unknown action "${action}".`);
|
|
183
163
|
}
|
|
@@ -8,6 +8,7 @@ exports.getActiveProject = getActiveProject;
|
|
|
8
8
|
exports.registerTieredTool = registerTieredTool;
|
|
9
9
|
const mcp_tiers_1 = require("../mcp-tiers");
|
|
10
10
|
const auth_1 = require("../../auth");
|
|
11
|
+
const agent_tier_1 = require("../../agent-tier");
|
|
11
12
|
/**
|
|
12
13
|
* Calls the app's own REST API over loopback using the MASTER token (held
|
|
13
14
|
* server-side, never exposed to the MCP client). This reuses every router's
|
|
@@ -119,9 +120,27 @@ function registerTieredTool(server, ctx, spec) {
|
|
|
119
120
|
description: spec.description,
|
|
120
121
|
inputSchema: spec.inputSchema,
|
|
121
122
|
annotations: tierAnnotations(hintTier),
|
|
122
|
-
}, async (args) => {
|
|
123
|
+
}, async (args, extra) => {
|
|
124
|
+
// In-app agent: a per-request active-project header (loopback-only, set by
|
|
125
|
+
// the agent's bridge from the Cursor-style selector) pins the project for
|
|
126
|
+
// this call so project-scoped tools resolve without specrails_select_project.
|
|
127
|
+
const projectHeader = extra?.requestInfo?.headers?.[agent_tier_1.AGENT_PROJECT_HEADER];
|
|
128
|
+
if (projectHeader != null) {
|
|
129
|
+
const pid = Array.isArray(projectHeader) ? projectHeader[0] : projectHeader;
|
|
130
|
+
if (typeof pid === 'string' && pid.trim())
|
|
131
|
+
setActiveProject(pid.trim());
|
|
132
|
+
}
|
|
123
133
|
const tier = typeof spec.tier === 'function' ? spec.tier(args ?? {}) : spec.tier;
|
|
124
|
-
|
|
134
|
+
// In-app agent: when the request carries the loopback-only agent-tier header,
|
|
135
|
+
// enforce the cumulative ladder instead of the external Settings checkboxes
|
|
136
|
+
// (design D4). Absent header → external client → unchanged Settings gate.
|
|
137
|
+
const agentLevel = (0, agent_tier_1.levelFromHeader)(extra?.requestInfo?.headers?.[agent_tier_1.AGENT_TIER_HEADER]);
|
|
138
|
+
if (agentLevel !== null) {
|
|
139
|
+
if (!(0, agent_tier_1.levelAllowsTier)(agentLevel, tier)) {
|
|
140
|
+
return errorResult((0, mcp_tiers_1.tierRefusalMessage)(tier));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (!(0, mcp_tiers_1.isTierEnabled)(ctx.desktopDb, tier)) {
|
|
125
144
|
return errorResult((0, mcp_tiers_1.tierRefusalMessage)(tier));
|
|
126
145
|
}
|
|
127
146
|
try {
|
|
@@ -67,7 +67,21 @@ function registerSetupRoutes(deps) {
|
|
|
67
67
|
const requested = (req.body ?? {});
|
|
68
68
|
const provider = typeof requested.provider === 'string' ? requested.provider : undefined;
|
|
69
69
|
res.status(202).json({ ok: true });
|
|
70
|
-
|
|
70
|
+
// One-shot multi-provider install: an explicit `providers` list, or `all:true`
|
|
71
|
+
// to install every provider the project is registered with (used by the MCP/
|
|
72
|
+
// agent so a single `install` provisions them all). Else single-provider.
|
|
73
|
+
const explicit = Array.isArray(requested.providers)
|
|
74
|
+
? requested.providers.filter((p) => typeof p === 'string')
|
|
75
|
+
: undefined;
|
|
76
|
+
if (explicit && explicit.length > 0) {
|
|
77
|
+
setupManager.startInstallProviders(project.id, project.path, project.slug, explicit);
|
|
78
|
+
}
|
|
79
|
+
else if (requested.all === true) {
|
|
80
|
+
setupManager.startInstallProviders(project.id, project.path, project.slug, project.providers);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
setupManager.startInstall(project.id, project.path, project.slug, provider);
|
|
84
|
+
}
|
|
71
85
|
});
|
|
72
86
|
router.post('/:projectId/enrich/start', (req, res) => {
|
|
73
87
|
const { project, setupManager } = ctx(req);
|