specrails-desktop 2.18.2 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/client/dist/assets/{ActivityFeedPage-mGnv5SOe.js → ActivityFeedPage-C0_k6n5T.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-NHUCEnTh.js +1 -0
- package/client/dist/assets/AgentModeCodePane-jddXrhPY.js +2 -0
- package/client/dist/assets/AgentsPage-BPjf6bId.js +86 -0
- package/client/dist/assets/AnalyticsPage-BaJjj5mO.js +1 -0
- package/client/dist/assets/{BarChart-BqHUOnl9.js → BarChart-HPiao--v.js} +1 -1
- package/client/dist/assets/CodePage-CAD4KfkC.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-CR-m97Ui.js → DesktopAnalyticsPage-B2RBxIvj.js} +1 -1
- package/client/dist/assets/DocsDialog-BJDvUEGj.js +11 -0
- package/client/dist/assets/DocsPage-B6H-DBs8.js +11 -0
- package/client/dist/assets/{ExportDropdown-C-o1Q4ef.js → ExportDropdown-CYMcbLTD.js} +1 -1
- package/client/dist/assets/IntegrationsPage-Dx_UpQVk.js +3 -0
- package/client/dist/assets/JobDetailPage-BlTnsRAN.js +16 -0
- package/client/dist/assets/JobsPage-EB0PbXOk.js +1 -0
- package/client/dist/assets/LoopBuilderPage-DfWfhhJY.js +7 -0
- package/client/dist/assets/LoopsPage-DCVATTv5.js +1 -0
- package/client/dist/assets/{addspec-B9dY_F5T.js → addspec-BXV6sx5l.js} +1 -1
- package/client/dist/assets/{addspec-tbxr3sHa.js → addspec-CS895X6A.js} +1 -1
- package/client/dist/assets/{addspec-W0r16BOC2.js → addspec-CXfEOrD42.js} +1 -1
- package/client/dist/assets/{addspec-D43TlMVp2.js → addspec-D28kw9ow2.js} +1 -1
- package/client/dist/assets/{addspec-B9nhMikb.js → addspec-D39EEg02.js} +1 -1
- package/client/dist/assets/{addspec-DfgIZ5lO.js → addspec-DC1tgsFG.js} +1 -1
- package/client/dist/assets/{addspec-BtNaJHu2.js → addspec-DcHALPEp.js} +1 -1
- package/client/dist/assets/{addspec-BloGn_ey.js → addspec-DxW6oPsk.js} +1 -1
- package/client/dist/assets/{agent-Bm2tPrdr.js → agent-B5Ycau5M.js} +1 -1
- package/client/dist/assets/{agent-DMUrz9ZS2.js → agent-BEz08l4_2.js} +1 -1
- package/client/dist/assets/{agent-C4bO1l_v.js → agent-BIX51CEA.js} +1 -1
- package/client/dist/assets/{agent-9WdSxPU5.js → agent-Bc9Kwf65.js} +1 -1
- package/client/dist/assets/{agent-pO8x4jbR.js → agent-BiM7puyn.js} +1 -1
- package/client/dist/assets/{agent-CgKsh88Z2.js → agent-C0kYSv3m2.js} +1 -1
- package/client/dist/assets/agent-CCzWlfqs.js +1 -0
- package/client/dist/assets/{agent-ASIyVcg0.js → agent-DiCSo31C.js} +1 -1
- package/client/dist/assets/{agents-DfGvYtpq2.js → agents-BFrHy5d-2.js} +1 -1
- package/client/dist/assets/{agents-Dli56gr82.js → agents-BFy2Kq_k2.js} +1 -1
- package/client/dist/assets/{agents-C07al8rI.js → agents-BXDCFJQa.js} +1 -1
- package/client/dist/assets/{agents-BAxAwHy-.js → agents-BySH0Gvw.js} +1 -1
- package/client/dist/assets/{agents-Eqw_AQ6H.js → agents-CTdwacTO.js} +1 -1
- package/client/dist/assets/{agents-BjT_xLjv.js → agents-Cev2oFfX.js} +1 -1
- package/client/dist/assets/{agents-BUYBb825.js → agents-CsDEv4Fj.js} +1 -1
- package/client/dist/assets/{agents-52t8NVpS.js → agents-z0kA-y0Q.js} +1 -1
- package/client/dist/assets/dashboard-Bl2_Yjs6.js +1 -0
- package/client/dist/assets/dashboard-C_vS9RaM2.js +1 -0
- package/client/dist/assets/dashboard-CcEpALV_.js +1 -0
- package/client/dist/assets/dashboard-CfltY66K.js +1 -0
- package/client/dist/assets/dashboard-CoED_41r.js +1 -0
- package/client/dist/assets/dashboard-DLeC5ziO.js +1 -0
- package/client/dist/assets/dashboard-DxEPkALo2.js +1 -0
- package/client/dist/assets/dashboard-MgDVmaYS2.js +1 -0
- package/client/dist/assets/{dist-js-CUegfF6k.js → dist-js-ClEfL6Bo.js} +1 -1
- package/client/dist/assets/{dist-js-BHhtSerX.js → dist-js-b2_z7zAi.js} +1 -1
- package/client/dist/assets/index-9yNUBwEi.css +2 -0
- package/client/dist/assets/{index-B7vB20Jw.js → index-BeujshsU.js} +57 -57
- package/client/dist/assets/{lib-PQoHlR5u.js → lib-CfphudAm.js} +1 -1
- package/client/dist/assets/loops-BEUiCzEI.js +1 -0
- package/client/dist/assets/loops-BlrQiK122.js +1 -0
- package/client/dist/assets/loops-Bs0ectZ32.js +1 -0
- package/client/dist/assets/loops-CLZV8HHY2.js +1 -0
- package/client/dist/assets/loops-CQuuMlyZ.js +1 -0
- package/client/dist/assets/loops-DuuWQWTI.js +1 -0
- package/client/dist/assets/loops-KOTryzk5.js +1 -0
- package/client/dist/assets/loops-t1mUZtf0.js +1 -0
- package/client/dist/assets/nav--1ErXZrS.js +1 -0
- package/client/dist/assets/nav-18nqSJ8h.js +1 -0
- package/client/dist/assets/nav-BuonHb17.js +1 -0
- package/client/dist/assets/nav-C-sCoOLY2.js +1 -0
- package/client/dist/assets/nav-ClXz_3Ic2.js +1 -0
- package/client/dist/assets/nav-CtqgSQeE2.js +1 -0
- package/client/dist/assets/nav-S3YvCaVv.js +1 -0
- package/client/dist/assets/nav-czg8NkN-.js +1 -0
- package/client/dist/assets/settings-BOZBX-Vq.js +1 -0
- package/client/dist/assets/settings-CX29QcQW.js +1 -0
- package/client/dist/assets/settings-CfOWHPzc2.js +1 -0
- package/client/dist/assets/settings-DaXhxNug2.js +1 -0
- package/client/dist/assets/settings-DmyDpuzu.js +1 -0
- package/client/dist/assets/settings-DwPRLcxr2.js +1 -0
- package/client/dist/assets/settings-MjYVJvDE.js +1 -0
- package/client/dist/assets/settings-zJFdTzKE.js +1 -0
- package/client/dist/assets/{setup-BYoDYoPY2.js → setup-BmXfxlzA2.js} +1 -1
- package/client/dist/assets/{setup-faMApo0U2.js → setup-BxVydxbl2.js} +1 -1
- package/client/dist/assets/{setup-C5UbM0RP.js → setup-DIRZ1Lf-.js} +1 -1
- package/client/dist/assets/{setup-Bf9eLKxU.js → setup-DwbKSnKQ.js} +1 -1
- package/client/dist/assets/{setup-JFkWWZnR.js → setup-Dx13pESZ.js} +1 -1
- package/client/dist/assets/{setup-CqGrWb6G.js → setup-G4ZvDKxX.js} +1 -1
- package/client/dist/assets/{setup-tloaTobG2.js → setup-SLAi4xxQ2.js} +1 -1
- package/client/dist/assets/{setup-4us-Bz3H.js → setup-Z01j3st4.js} +1 -1
- package/client/dist/assets/{upload-PnJDPHZH.js → upload-Ox9jUq1X.js} +1 -1
- package/client/dist/assets/{value-BTDefcOV.js → value-BeQVX5gN.js} +1 -1
- package/client/dist/index.html +10 -10
- package/docs/codex.md +5 -5
- package/docs/customizing.md +4 -4
- package/docs/gemini.md +2 -2
- package/docs/getting-started.md +1 -1
- package/docs/guide/de/integrations/1-ai-providers.md +2 -2
- package/docs/guide/de/integrations/5-mcp-server.md +20 -1
- package/docs/guide/de/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/de/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/de/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/en/integrations/1-ai-providers.md +2 -2
- package/docs/guide/en/integrations/5-mcp-server.md +20 -1
- package/docs/guide/en/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/en/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/en/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/es/integrations/1-ai-providers.md +2 -2
- package/docs/guide/es/integrations/5-mcp-server.md +20 -1
- package/docs/guide/es/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/es/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/es/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/fr/integrations/1-ai-providers.md +2 -2
- package/docs/guide/fr/integrations/5-mcp-server.md +20 -1
- package/docs/guide/fr/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/fr/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/fr/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/it/integrations/1-ai-providers.md +2 -2
- package/docs/guide/it/integrations/5-mcp-server.md +20 -1
- package/docs/guide/it/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/it/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/it/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/ja/integrations/1-ai-providers.md +2 -2
- package/docs/guide/ja/integrations/5-mcp-server.md +20 -1
- package/docs/guide/ja/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/ja/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/ja/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/pt/integrations/1-ai-providers.md +2 -2
- package/docs/guide/pt/integrations/5-mcp-server.md +20 -1
- package/docs/guide/pt/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/pt/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/pt/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/zh/integrations/1-ai-providers.md +2 -2
- package/docs/guide/zh/integrations/5-mcp-server.md +20 -1
- package/docs/guide/zh/pipeline/1-rails-and-jobs.md +4 -4
- package/docs/guide/zh/pipeline/2-the-job-detail-view.md +1 -1
- package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/zh/pipeline/5-the-loop-builder.md +2 -2
- package/docs/internals/switch-to-agent-mode-design.md +301 -0
- package/docs/internals/visual-design-audit.md +184 -0
- package/docs/mcp.md +26 -1
- package/docs/running-pipelines.md +10 -10
- package/docs/tracking-cost.md +1 -1
- package/package.json +1 -1
- package/server/dist/agent-chat-manager.js +107 -33
- package/server/dist/agent-chat-router.js +170 -8
- package/server/dist/agent-cwd-manager.js +2 -47
- package/server/dist/agent-operator-prompt.js +277 -0
- package/server/dist/agent-store.js +27 -5
- package/server/dist/attachment-manager.js +138 -0
- package/server/dist/desktop-db.js +15 -0
- package/server/dist/loop-factory.js +12 -2
- package/server/dist/mcp/guide.js +186 -51
- package/server/dist/mcp/tools/analytics.js +1 -1
- package/server/dist/mcp/tools/app-settings.js +45 -5
- package/server/dist/mcp/tools/chat.js +9 -2
- package/server/dist/mcp/tools/code.js +3 -2
- package/server/dist/mcp/tools/jobs.js +18 -6
- package/server/dist/mcp/tools/loops.js +57 -5
- package/server/dist/mcp/tools/meta.js +43 -3
- package/server/dist/mcp/tools/rails.js +6 -6
- package/server/dist/mcp/tools/setup.js +2 -1
- package/server/dist/mcp/tools/specs.js +60 -38
- package/server/dist/mcp/tools/types.js +17 -8
- package/server/dist/mcp/tools/watch.js +71 -8
- package/server/dist/project-router-helpers.js +1 -1
- package/server/dist/project-router-tickets.js +43 -4
- package/server/dist/providers/claude-adapter.js +6 -0
- package/server/dist/providers/codex-adapter.js +10 -0
- package/server/dist/providers/gemini-adapter.js +3 -0
- package/server/dist/rails-router.js +8 -17
- package/server/dist/spec-models.js +1 -0
- package/client/dist/assets/AgentsPage-BH1isg5j.js +0 -86
- package/client/dist/assets/AnalyticsPage-ByyshYRI.js +0 -1
- package/client/dist/assets/CodePage-CU7T_HYs.js +0 -2
- package/client/dist/assets/DocsDialog-CEmZp_8V.js +0 -11
- package/client/dist/assets/DocsPage-DYbAQ1AT.js +0 -11
- package/client/dist/assets/IntegrationsPage-C6fKdwVH.js +0 -3
- package/client/dist/assets/JobDetailPage-CKfIfBgE.js +0 -16
- package/client/dist/assets/JobsPage-nBng0riZ.js +0 -1
- package/client/dist/assets/LoopBuilderPage-Co_TYqYk.js +0 -7
- package/client/dist/assets/LoopsPage-a2hd37Ya.js +0 -1
- package/client/dist/assets/agent-Dwkz5mPS.js +0 -1
- package/client/dist/assets/dashboard-BTiH361F.js +0 -1
- package/client/dist/assets/dashboard-COSm_14E.js +0 -1
- package/client/dist/assets/dashboard-CfOs70FN2.js +0 -1
- package/client/dist/assets/dashboard-Cyzp4ox9.js +0 -1
- package/client/dist/assets/dashboard-CzHDp14_2.js +0 -1
- package/client/dist/assets/dashboard-D6Woy2B5.js +0 -1
- package/client/dist/assets/dashboard-DwbH4oVH.js +0 -1
- package/client/dist/assets/dashboard-cWhU3krA2.js +0 -1
- package/client/dist/assets/index-B0FxQALR.css +0 -2
- package/client/dist/assets/loops-BDhEfnx82.js +0 -1
- package/client/dist/assets/loops-BM5QggwH.js +0 -1
- package/client/dist/assets/loops-CPjLAAxj.js +0 -1
- package/client/dist/assets/loops-D8Iu6Jss.js +0 -1
- package/client/dist/assets/loops-DKnk79TB2.js +0 -1
- package/client/dist/assets/loops-DLW0aFMm.js +0 -1
- package/client/dist/assets/loops-Dcv3dFy_2.js +0 -1
- package/client/dist/assets/loops-y7wFRx6M.js +0 -1
- package/client/dist/assets/nav-1hj2izqB2.js +0 -1
- package/client/dist/assets/nav-BBUKMAu-2.js +0 -1
- package/client/dist/assets/nav-CLqkP-26.js +0 -1
- package/client/dist/assets/nav-Cv46L837.js +0 -1
- package/client/dist/assets/nav-DE3yWQw6.js +0 -1
- package/client/dist/assets/nav-DgA-rjLk2.js +0 -1
- package/client/dist/assets/nav-EG2pr6vN.js +0 -1
- package/client/dist/assets/nav-r3mIJVfU.js +0 -1
- package/client/dist/assets/settings-BKmORxlB2.js +0 -1
- package/client/dist/assets/settings-BVv2JgQ8.js +0 -1
- package/client/dist/assets/settings-Bghm3pAV.js +0 -1
- package/client/dist/assets/settings-BuC_aplX.js +0 -1
- package/client/dist/assets/settings-Bw_Qk8E32.js +0 -1
- package/client/dist/assets/settings-CAKgJv7p.js +0 -1
- package/client/dist/assets/settings-CEUgk1Ck.js +0 -1
- package/client/dist/assets/settings-C_PDE20s2.js +0 -1
- /package/client/dist/assets/{activity-Uj576ckT.js → activity-BlvN5rhP.js} +0 -0
- /package/client/dist/assets/{activity-w1qMFwxh.js → activity-C5SeKbom.js} +0 -0
- /package/client/dist/assets/{activity-BySXFT2J2.js → activity-DIJexk6v2.js} +0 -0
- /package/client/dist/assets/{activity-B82z3Pna.js → activity-DLdwUYv7.js} +0 -0
- /package/client/dist/assets/{activity-BVpZrs0J.js → activity-DOKV_Wyf.js} +0 -0
- /package/client/dist/assets/{activity-BId0pwuS2.js → activity-DVuiy8TI2.js} +0 -0
- /package/client/dist/assets/{activity-DIWnV0Pl.js → activity-Dsf3J7iW.js} +0 -0
- /package/client/dist/assets/{agentstudio-C7xxqVWn.js → agentstudio-B8H2H4Db2.js} +0 -0
- /package/client/dist/assets/{agentstudio-D-UoNAIA.js → agentstudio-B9zthaTJ.js} +0 -0
- /package/client/dist/assets/{agentstudio-0o3XKrcy.js → agentstudio-BDMpU01s.js} +0 -0
- /package/client/dist/assets/{agentstudio-Bu8m5jDw.js → agentstudio-CSZo7p8K.js} +0 -0
- /package/client/dist/assets/{agentstudio-ObTpVbBP.js → agentstudio-CdD6J23W.js} +0 -0
- /package/client/dist/assets/{agentstudio-PzFB3vfh2.js → agentstudio-D80fZu_M2.js} +0 -0
- /package/client/dist/assets/{agentstudio-OJjjz6Uf2.js → agentstudio-EuKglkaF2.js} +0 -0
- /package/client/dist/assets/{aiedit-DRrNiaB4.js → aiedit-B_VOTUo42.js} +0 -0
- /package/client/dist/assets/{aiedit-sP_iao2j.js → aiedit-Cxoe_0wv.js} +0 -0
- /package/client/dist/assets/{aiedit-DAM_WRAl2.js → aiedit-D59sPapq2.js} +0 -0
- /package/client/dist/assets/{aiedit-BaLZalLa.js → aiedit-DX3BBpXF.js} +0 -0
- /package/client/dist/assets/{aiedit-BIQqv2XM2.js → aiedit-GYOYWCHJ2.js} +0 -0
- /package/client/dist/assets/{aiedit-BjlUzasF.js → aiedit-TON-4N9S.js} +0 -0
- /package/client/dist/assets/{aiedit-BmDufyGU.js → aiedit-ybQmdsST.js} +0 -0
- /package/client/dist/assets/{analytics-MVJRjcY52.js → analytics-B2jjXLCP2.js} +0 -0
- /package/client/dist/assets/{analytics-C4z_NgJZ.js → analytics-BTkXLTfa.js} +0 -0
- /package/client/dist/assets/{analytics-DL2vJCbq.js → analytics-BotqRU_R.js} +0 -0
- /package/client/dist/assets/{analytics-e1mkNTgy2.js → analytics-Ck3vl2Qo2.js} +0 -0
- /package/client/dist/assets/{analytics-Ds_PNxtO2.js → analytics-CqMJQb7N.js} +0 -0
- /package/client/dist/assets/{analytics-B_rxNC9X.js → analytics-DGOoMkaZ.js} +0 -0
- /package/client/dist/assets/{analytics-BDqqCzN9.js → analytics-DL7uwNAI2.js} +0 -0
- /package/client/dist/assets/{attachments-BP0Ac1yt.js → attachments-7w-BR2V2.js} +0 -0
- /package/client/dist/assets/{attachments-CPBVeHX72.js → attachments-B5QX1Xfa2.js} +0 -0
- /package/client/dist/assets/{attachments-Db7JfA8a.js → attachments-BcE7kZG-2.js} +0 -0
- /package/client/dist/assets/{attachments-CJaO1vCH.js → attachments-BsJJXFzT.js} +0 -0
- /package/client/dist/assets/{attachments-8QCKHCEF2.js → attachments-Cbh4AwjP.js} +0 -0
- /package/client/dist/assets/{attachments-CV2uaTGE.js → attachments-D0fGlFve.js} +0 -0
- /package/client/dist/assets/{attachments-CaOjdN332.js → attachments-D3DJpd3e2.js} +0 -0
- /package/client/dist/assets/{browser-C9rUUxo4.js → browser-9GR11iTi.js} +0 -0
- /package/client/dist/assets/{browser-CEqx11iy.js → browser-BOxg0p3n.js} +0 -0
- /package/client/dist/assets/{browser-543jbxE4.js → browser-BSh8xUWV.js} +0 -0
- /package/client/dist/assets/{browser-CLC0etB_2.js → browser-CaV3BJNY2.js} +0 -0
- /package/client/dist/assets/{browser-0xeW8fUa2.js → browser-CmWGMRGf2.js} +0 -0
- /package/client/dist/assets/{browser-ExmELH702.js → browser-D6wbpBOL2.js} +0 -0
- /package/client/dist/assets/{browser-DyG2l9Wa.js → browser-dsgDU1HB.js} +0 -0
- /package/client/dist/assets/{chat-DagUyoVA.js → chat-B90iLDI4.js} +0 -0
- /package/client/dist/assets/{chat-Cu6F3d6g2.js → chat-CAo0jCnj2.js} +0 -0
- /package/client/dist/assets/{chat-CN8BMAMc.js → chat-CW54IP3u.js} +0 -0
- /package/client/dist/assets/{chat-NQPCBQo72.js → chat-CYHUUW0p2.js} +0 -0
- /package/client/dist/assets/{chat-CCytD3P8.js → chat-D1PXX_p2.js} +0 -0
- /package/client/dist/assets/{chat-IjutwlBg.js → chat-DhpcWjOf.js} +0 -0
- /package/client/dist/assets/{chat-vVpwkOp52.js → chat-cFG-UfRA2.js} +0 -0
- /package/client/dist/assets/{code-Dhb6jbAU.js → code--qUk_yn-.js} +0 -0
- /package/client/dist/assets/{code-Ce-nBIwj.js → code-B1aOMCVV.js} +0 -0
- /package/client/dist/assets/{code-BaG05zK62.js → code-B5UrmjaE2.js} +0 -0
- /package/client/dist/assets/{code-Dap54vOb.js → code-CjBHU0nw.js} +0 -0
- /package/client/dist/assets/{code-_NOCo-Ol2.js → code-Cjv4_HkK2.js} +0 -0
- /package/client/dist/assets/{code-32l6Naxu2.js → code-D7GLAjrz2.js} +0 -0
- /package/client/dist/assets/{code-C5cibF2F.js → code-DZKjfzBN.js} +0 -0
- /package/client/dist/assets/{commands-Cc2WpuXa.js → commands-B9XaopQC.js} +0 -0
- /package/client/dist/assets/{commands-k9wbNYoi.js → commands-BCx1uDIE.js} +0 -0
- /package/client/dist/assets/{commands-CM99Upsz2.js → commands-Bhw9Hqsa2.js} +0 -0
- /package/client/dist/assets/{commands-Bc8y9eNo2.js → commands-D0RnooQF2.js} +0 -0
- /package/client/dist/assets/{commands-Bl3-KVfj.js → commands-DuaQT-it.js} +0 -0
- /package/client/dist/assets/{commands-DASXJD-l.js → commands-MqNuGGO4.js} +0 -0
- /package/client/dist/assets/{commands-C5WQ9blx2.js → commands-oB9q2vy_2.js} +0 -0
- /package/client/dist/assets/{common-CHARW6MZ2.js → common-BXzqeuiC2.js} +0 -0
- /package/client/dist/assets/{common-0aY9HQBP.js → common-BaJ6MF7T.js} +0 -0
- /package/client/dist/assets/{common-CQCJzAQq2.js → common-C-jaOdxz2.js} +0 -0
- /package/client/dist/assets/{common-DNhhqjlJ.js → common-CKjy-R8-.js} +0 -0
- /package/client/dist/assets/{common-YdyZtmaI2.js → common-CRd-Ge5u2.js} +0 -0
- /package/client/dist/assets/{common-5jScBJqt.js → common-DPGR3Tfo.js} +0 -0
- /package/client/dist/assets/{common-BdaRciTu.js → common-wEB9RBdf.js} +0 -0
- /package/client/dist/assets/{explore-ChtxIiSM.js → explore-B_79NLR5.js} +0 -0
- /package/client/dist/assets/{explore-BzdMEpuf.js → explore-D-htKul_.js} +0 -0
- /package/client/dist/assets/{explore-B82VMUJ_.js → explore-D5b2jgvR.js} +0 -0
- /package/client/dist/assets/{explore-DfcUfiPw2.js → explore-Dvp-5qOw2.js} +0 -0
- /package/client/dist/assets/{explore-CbW0381i2.js → explore-FaKfWCr72.js} +0 -0
- /package/client/dist/assets/{explore-BGz1rvQE.js → explore-IS8VyaSZ.js} +0 -0
- /package/client/dist/assets/{explore-yRF7wFSp2.js → explore-OZhWV0Eb2.js} +0 -0
- /package/client/dist/assets/{format-command-D96da4fZ.js → format-command-CHImQv6W.js} +0 -0
- /package/client/dist/assets/{integrations-CnrX7vqw2.js → integrations-B97cGWfo2.js} +0 -0
- /package/client/dist/assets/{integrations-BJvrlcc7.js → integrations-Bp3leAh3.js} +0 -0
- /package/client/dist/assets/{integrations-CPKYkG36.js → integrations-C3Ma3GdM.js} +0 -0
- /package/client/dist/assets/{integrations-BA5pM05t.js → integrations-C5MUA-0-.js} +0 -0
- /package/client/dist/assets/{integrations-B0OBPU9_.js → integrations-CiQbCn_W.js} +0 -0
- /package/client/dist/assets/{integrations-DeJFRyXz2.js → integrations-Du_0rDfi2.js} +0 -0
- /package/client/dist/assets/{integrations-DBou159M2.js → integrations-t4X5UVcx2.js} +0 -0
- /package/client/dist/assets/{jira-mi37H4Kt.js → jira-B1XaR6fj.js} +0 -0
- /package/client/dist/assets/{jira-Srx2P5zS.js → jira-BCHx9zUF.js} +0 -0
- /package/client/dist/assets/{jira-DeotPx6P2.js → jira-BqXyykbt2.js} +0 -0
- /package/client/dist/assets/{jira-BwLBgmfI2.js → jira-BzFvFn7t2.js} +0 -0
- /package/client/dist/assets/{jira-BDgxAFTF2.js → jira-D6IDTIsc2.js} +0 -0
- /package/client/dist/assets/{jira-NwlUCcQD.js → jira-DSZ5xFRl.js} +0 -0
- /package/client/dist/assets/{jira-D3GGzXOI.js → jira-DdEKW9Pu.js} +0 -0
- /package/client/dist/assets/{jobs-D8adm2BX.js → jobs-BX9dP3Qn.js} +0 -0
- /package/client/dist/assets/{jobs-B56vQEkh2.js → jobs-BgHEgCWk2.js} +0 -0
- /package/client/dist/assets/{jobs-K_Y8KAZ2.js → jobs-CU-khJTt.js} +0 -0
- /package/client/dist/assets/{jobs-BYIk6Tg_.js → jobs-Ce0SE81t.js} +0 -0
- /package/client/dist/assets/{jobs-C-lM-iax2.js → jobs-CeOcGHd_2.js} +0 -0
- /package/client/dist/assets/{jobs-CYdevGgT.js → jobs-Ct5v2p6T.js} +0 -0
- /package/client/dist/assets/{jobs-OwM0ZWhI2.js → jobs-m7L0K9uC2.js} +0 -0
- /package/client/dist/assets/{mcp-D3E4_Mmk2.js → mcp-4QbfLPa4.js} +0 -0
- /package/client/dist/assets/{mcp-B6nwJJmR.js → mcp-CXy61khH.js} +0 -0
- /package/client/dist/assets/{mcp-CNgFiTEh.js → mcp-CmOBPDjE.js} +0 -0
- /package/client/dist/assets/{mcp-mupPuPDO2.js → mcp-NlLc9T8u2.js} +0 -0
- /package/client/dist/assets/{mcp-B4irfLJ2.js → mcp-_DUUXTHB2.js} +0 -0
- /package/client/dist/assets/{mcp-BP7PpbDr2.js → mcp-dlOyUQQy2.js} +0 -0
- /package/client/dist/assets/{mcp-BOoEGTSQ.js → mcp-zqSVP7nA.js} +0 -0
- /package/client/dist/assets/{specs-D4z5d8uq.js → specs-57pue7UQ.js} +0 -0
- /package/client/dist/assets/{specs-CWNKAScX2.js → specs-BWQ-0EXt2.js} +0 -0
- /package/client/dist/assets/{specs-B8mwScoM2.js → specs-BYSOlQRw2.js} +0 -0
- /package/client/dist/assets/{specs-B5XOoH-02.js → specs-CkP0B28v2.js} +0 -0
- /package/client/dist/assets/{specs-DgvIRZtM.js → specs-RSYuLgF4.js} +0 -0
- /package/client/dist/assets/{specs-DuRzE5wE.js → specs-d-zU7_3Q.js} +0 -0
- /package/client/dist/assets/{specs-Bj_3fDrQ.js → specs-nM5Cpcqe.js} +0 -0
- /package/client/dist/assets/{terminal-DoMTHedv2.js → terminal-Adi3W-GZ2.js} +0 -0
- /package/client/dist/assets/{terminal-DOwfkxqa2.js → terminal-BA6FCZna2.js} +0 -0
- /package/client/dist/assets/{terminal-CH0fdHvP.js → terminal-BCIUSkrg.js} +0 -0
- /package/client/dist/assets/{terminal-B2sExUis.js → terminal-C8KlD61D.js} +0 -0
- /package/client/dist/assets/{terminal-DjSSa5qP.js → terminal-D3RTuBwy.js} +0 -0
- /package/client/dist/assets/{terminal-w0i-OCp32.js → terminal-DCkOEjSj2.js} +0 -0
- /package/client/dist/assets/{terminal-CPMigUX7.js → terminal-DOuNm2BI.js} +0 -0
- /package/client/dist/assets/{tickets-D00mSt832.js → tickets-B2q36GlQ2.js} +0 -0
- /package/client/dist/assets/{tickets-CQTana1u.js → tickets-Bsyv_znj.js} +0 -0
- /package/client/dist/assets/{tickets-D7CSuWjO.js → tickets-C_UPra_1.js} +0 -0
- /package/client/dist/assets/{tickets-heDAaj8C2.js → tickets-D72LbUtU2.js} +0 -0
- /package/client/dist/assets/{tickets-DvbFg_-c2.js → tickets-DDjU7UfE2.js} +0 -0
- /package/client/dist/assets/{tickets-onKZz6Dd.js → tickets-DR4ZrPMf.js} +0 -0
- /package/client/dist/assets/{tickets-Dq7HDy8n.js → tickets-DiUA3rXq.js} +0 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── Single source of truth for the in-app operator agent prompts ─────────────
|
|
3
|
+
// OPERATOR_INSTRUCTIONS is the CANONICAL prompt: written to CLAUDE.md/AGENTS.md/
|
|
4
|
+
// GEMINI.md in ~/.specrails/agent-cwd/ — the only channel that reaches all three
|
|
5
|
+
// providers (codex/gemini have no --system-prompt flag). OPERATOR_SYSTEM_PROMPT
|
|
6
|
+
// is a compact distillation passed via --system-prompt on claude only (it
|
|
7
|
+
// REPLACES the CLI's default system prompt — keep it).
|
|
8
|
+
//
|
|
9
|
+
// BYTE-STABILITY CONTRACT: both constants must stay static (no timestamps, no
|
|
10
|
+
// interpolation, no live data) so Anthropic prompt caching hits on turns 2+.
|
|
11
|
+
// Dynamic per-turn state (pinned project, permission level, provider) rides the
|
|
12
|
+
// user-turn prefix in AgentChatManager — never add it here.
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.OPERATOR_SYSTEM_PROMPT = exports.OPERATOR_INSTRUCTIONS = void 0;
|
|
15
|
+
exports.OPERATOR_INSTRUCTIONS = `# Specrails Operator Agent
|
|
16
|
+
|
|
17
|
+
You are the Specrails operator: an agent embedded INSIDE the Specrails Desktop
|
|
18
|
+
app, chatting with the user from the app's own agent panel. You drive the app on
|
|
19
|
+
their behalf through the \`specrails_*\` MCP tools. Acting through the tools is the
|
|
20
|
+
same as clicking the UI — every mutation appears LIVE in the interface the user
|
|
21
|
+
is looking at (Specs board, rail headers, job logs, Analytics, Code explorer).
|
|
22
|
+
Refer the user to those surfaces by name when it helps.
|
|
23
|
+
|
|
24
|
+
## The platform in one page
|
|
25
|
+
|
|
26
|
+
Specrails manages multiple registered repositories ("projects") and runs AI
|
|
27
|
+
coding pipelines over them.
|
|
28
|
+
|
|
29
|
+
- **Spec / ticket** — the unit of work in a project's backlog. Statuses: \`draft\`,
|
|
30
|
+
\`todo\`, \`in_progress\`, \`done\`, \`cancelled\`, plus a \`needs_review\` boolean FLAG
|
|
31
|
+
on \`done\` specs (it is not a status). Priorities \`critical|high|medium|low\`;
|
|
32
|
+
priority may be null ONLY while status is \`draft\`. A spec can be an epic
|
|
33
|
+
(SMASH splits a large spec into child specs) and can be Jira-backed
|
|
34
|
+
(\`source: 'jira'\`).
|
|
35
|
+
- **Rail** — a persistent numbered launch slot that REMEMBERS its config across
|
|
36
|
+
launches (assigned tickets, mode, profile, engine, name). Modes: \`implement\`
|
|
37
|
+
(one pipeline job — Architect → Developer → Reviewer → Ship — over the rail's
|
|
38
|
+
tickets), \`batch-implement\` (dependency-aware waves), Freestyle (wire value
|
|
39
|
+
\`ultracode\` — hands the spec straight to the model, one job per ticket,
|
|
40
|
+
Claude-only, optional interactive in-job chat), \`loop\` (runs a saved
|
|
41
|
+
workflow graph per ticket). Launching spawns AI CLI processes that WRITE CODE,
|
|
42
|
+
RUN TESTS and COMMIT in the repo — it costs money and runs for minutes.
|
|
43
|
+
- **Job** — one spawned run. Outcomes mutate spec status AUTOMATICALLY: launch →
|
|
44
|
+
\`in_progress\`; success → \`done\`; revert → back to \`todo\`; partial confidence →
|
|
45
|
+
\`done\` + \`needs_review\`. NEVER patch a status the pipeline manages; only
|
|
46
|
+
correct statuses when the user explicitly asks.
|
|
47
|
+
- **Loop** — an app-level (cross-project) saved workflow graph. Author and
|
|
48
|
+
publish with \`specrails_loops\`; RUN it with
|
|
49
|
+
\`specrails_rails(launch, mode:'loop', loopId)\`.
|
|
50
|
+
- **Profile** — per-project agent-chain config (which agents, which models,
|
|
51
|
+
routing). Claude-only; forced to null on codex/gemini rails.
|
|
52
|
+
- **Provider / engine** — claude, codex or gemini. A project installs one or
|
|
53
|
+
more; AI-spawning actions may pick any installed one. Claude-only features:
|
|
54
|
+
profiles, Contract Refine, SMASH, Freestyle, interactive jobs. Cost is
|
|
55
|
+
authoritative on claude, estimated (~) on codex/gemini.
|
|
56
|
+
|
|
57
|
+
## How to work
|
|
58
|
+
|
|
59
|
+
- Target a project with \`specrails_select_project\` (or the \`projectId\`
|
|
60
|
+
argument). If none is pinned ("Home") and the request is project-specific, ASK
|
|
61
|
+
whether to create a project or search across all — do not guess.
|
|
62
|
+
- \`specrails_watch\` follows 202-accepted operations to completion (pass
|
|
63
|
+
\`projectId\` when one isn't pinned). A \`settled:false\` timeout does NOT mean
|
|
64
|
+
failure — re-watch with a larger \`untilMs\` (max 600000) or poll the domain
|
|
65
|
+
read (\`specrails_jobs(get)\`, \`specrails_specs(get)\`,
|
|
66
|
+
\`specrails_plugins(health)\`) to confirm the outcome. Never claim success from
|
|
67
|
+
the 202 acceptance alone.
|
|
68
|
+
- Prefer \`specrails_guide\` / \`specrails_search\` / \`specrails_describe\` to
|
|
69
|
+
discover the exact action and arguments before calling an unfamiliar tool.
|
|
70
|
+
- Ground claims about the user's code with
|
|
71
|
+
\`specrails_code(tree | read_file | summary)\` before asserting how the codebase
|
|
72
|
+
works; \`specrails_projects(get)\` returns the repo's absolute path.
|
|
73
|
+
- When you ask the user to pick between concrete choices, append a fenced code
|
|
74
|
+
block with language \`options\` at the very END of the reply, containing only a
|
|
75
|
+
JSON array of the choice labels (2-6 short strings, e.g.
|
|
76
|
+
\`["Option A", "Option B"]\`) — the app renders them as clickable chips the
|
|
77
|
+
user can tap to answer. Never emit this block when you are not asking the
|
|
78
|
+
user to choose.
|
|
79
|
+
|
|
80
|
+
## Permission ladder & confirmation rules
|
|
81
|
+
|
|
82
|
+
Your actions are gated by a cumulative level the user steers live with
|
|
83
|
+
Shift+Tab (or by clicking the tier chip): observe (read) ▸ edit (write) ▸
|
|
84
|
+
operate (launch AI, costs money) ▸ autonomous (delete/kill). If a tool is
|
|
85
|
+
refused, tell the user which level it needs and that Shift+Tab raises it —
|
|
86
|
+
never try to work around the refusal. When you are about to propose an action
|
|
87
|
+
above the current level, say so up front.
|
|
88
|
+
|
|
89
|
+
- NEVER call an ai-spawn action (rails launch, jobs spawn/interactive_turn,
|
|
90
|
+
specs create/generate/ai_edit/contract_refine/smash, chat send, agents
|
|
91
|
+
generate/test/refine, code regenerate_summary) without first proposing it in
|
|
92
|
+
plain words — what runs, on which project, which engine/model, roughly how
|
|
93
|
+
long and that it costs real tokens — and receiving an explicit yes for THAT
|
|
94
|
+
action.
|
|
95
|
+
- NEVER call a destructive action (delete, stop, cancel, purge, uninstall,
|
|
96
|
+
unregister, disconnect) without restating exactly what is destroyed, that it
|
|
97
|
+
is irreversible, and receiving an explicit yes naming it.
|
|
98
|
+
- One yes covers one action. Do not batch multiple launches or deletes under a
|
|
99
|
+
single confirmation unless the user explicitly asked for the batch.
|
|
100
|
+
- Reversible reads and writes (list/get, spec edits, rail config) need no
|
|
101
|
+
confirmation — act, then report what you did with ids.
|
|
102
|
+
|
|
103
|
+
## Think in specs (default stance)
|
|
104
|
+
|
|
105
|
+
When the user describes work to be done, the natural unit is a SPEC:
|
|
106
|
+
|
|
107
|
+
1. Check the backlog for duplicates first: \`specrails_specs(list)\`.
|
|
108
|
+
2. Capture the work as a spec — pick the right creation path (next section).
|
|
109
|
+
3. Once a spec lands, offer the next step: assign it to a rail and launch
|
|
110
|
+
(\`specrails_rails(set_tickets)\` → \`launch\`), with cost framing.
|
|
111
|
+
4. After a launch, watch the job and narrate progress and outcome honestly.
|
|
112
|
+
5. After expensive runs, offer \`specrails_analytics(spending)\`.
|
|
113
|
+
|
|
114
|
+
## Creating specs — pick the right path
|
|
115
|
+
|
|
116
|
+
- **Quick (AI-generated)** — \`specrails_specs(generate, idea, …)\`: one AI pass
|
|
117
|
+
structures the request into a full spec, exactly like the app's Add Spec →
|
|
118
|
+
Quick. Use for clear, well-scoped requests. Async (202). Operate level.
|
|
119
|
+
- **Spec refinement role-play (you)** — when the request is fuzzy, contested, or
|
|
120
|
+
high-stakes, DO NOT one-shot it. Run the refinement conversation yourself
|
|
121
|
+
(see "Spec refinement mode") and persist with \`commit_draft\`. No extra AI
|
|
122
|
+
spend; persisting needs only edit level.
|
|
123
|
+
- **Nested app Explore** — ONLY when the user explicitly wants the session to
|
|
124
|
+
live in the app UI (visible live draft, resumable "Continue Explore",
|
|
125
|
+
Contract Refine eligibility): \`specrails_chat(create, kind:'explore',
|
|
126
|
+
contextScope)\` → \`send\` turns → \`spec_draft\` → \`specrails_specs(commit_draft,
|
|
127
|
+
conversationId, …)\`. Spawns a second AI (double cost, operate level).
|
|
128
|
+
Bootstrap the first send with the text \`/specrails:explore-spec\` + blank line
|
|
129
|
+
+ the idea, and \`lightweight: true\`, \`maxTurns: 20\`.
|
|
130
|
+
- **Verbatim** — \`specrails_specs(from_prompt)\`: stores the given description
|
|
131
|
+
as-is with NO AI pass, but CANNOT set acceptanceCriteria or shortSummary.
|
|
132
|
+
Only when the user hands you finished text and wants it untouched; otherwise
|
|
133
|
+
prefer \`commit_draft\`.
|
|
134
|
+
- **Big features**: offer SMASH (\`specrails_specs(smash)\`) to split an epic
|
|
135
|
+
into children (Claude-only). **Recurring work**: offer a loop.
|
|
136
|
+
|
|
137
|
+
## Spec refinement mode (thinking partner)
|
|
138
|
+
|
|
139
|
+
When the user wants to shape, refine, or think through a piece of work — not
|
|
140
|
+
just "add a spec that says X" — become their thinking partner and build the
|
|
141
|
+
spec WITH them over several turns. You run this yourself, in this
|
|
142
|
+
conversation; do not open a nested Explore chat unless the user explicitly
|
|
143
|
+
asks for one in the app UI.
|
|
144
|
+
|
|
145
|
+
**Investigate first, then ask.** Before your first question, ground yourself
|
|
146
|
+
with read-only tools: \`specrails_specs(list)\` to find duplicates and learn the
|
|
147
|
+
project's label conventions, and \`specrails_code(tree / read_file / summary)\`
|
|
148
|
+
for the parts of the codebase the idea touches. A grounded clarification beats
|
|
149
|
+
five guess-questions. If a similar spec already exists, surface it FIRST and
|
|
150
|
+
ask whether to extend it or create a new one. Never recommend building
|
|
151
|
+
something that already exists — verify against the real code, not memory. Stop
|
|
152
|
+
reading as soon as you can ask a meaningful question.
|
|
153
|
+
|
|
154
|
+
**Question cadence.** Ask at most TWO well-aimed questions per turn, focused on
|
|
155
|
+
what actually changes the spec (scope, behaviour, edge cases, acceptance).
|
|
156
|
+
Surface trade-offs and risks the user may not have considered. Stop asking
|
|
157
|
+
once you have enough for a small, clear, testable spec — do not interrogate
|
|
158
|
+
past the point of usefulness. Offer 2-3 short literal reply options the user
|
|
159
|
+
can copy when it helps ("Settings page only", "Looks good — create it").
|
|
160
|
+
|
|
161
|
+
**Show the draft every turn.** End every turn that changed the draft with a
|
|
162
|
+
compact card in this exact shape (plain markdown, no code fences):
|
|
163
|
+
|
|
164
|
+
> **Draft so far** — <title or "untitled">
|
|
165
|
+
> Priority: <p> · Labels: <l1, l2> · Acceptance criteria: <n>
|
|
166
|
+
> New this turn: <one line>
|
|
167
|
+
> Open questions: <the questions you just asked, or "none">
|
|
168
|
+
|
|
169
|
+
Do NOT paste the full description body into every turn — only the card.
|
|
170
|
+
|
|
171
|
+
**Spec content contract** — match the shape of app-generated specs:
|
|
172
|
+
|
|
173
|
+
- \`title\` — short, imperative, English.
|
|
174
|
+
- \`shortSummary\` — one sentence, at most 240 characters.
|
|
175
|
+
- \`description\` — English markdown with five sections: \`## Problem Statement\`
|
|
176
|
+
(2-3 sentences), \`## Proposed Solution\` (3-5 sentences), \`## Out of Scope\`
|
|
177
|
+
(bullets), \`## Technical Considerations\` (bullets), \`## Estimated Complexity\`
|
|
178
|
+
(Low/Medium/High/Very High + one sentence). Never put a title heading or the
|
|
179
|
+
acceptance criteria inside the description — they are separate fields, and
|
|
180
|
+
the app appends criteria under \`## Acceptance Criteria\` automatically.
|
|
181
|
+
- \`acceptanceCriteria\` — a separate array of testable statements.
|
|
182
|
+
- \`labels\`; \`priority\` (default \`medium\`).
|
|
183
|
+
|
|
184
|
+
Spec CONTENT is always written in English; your conversational prose follows
|
|
185
|
+
the user's language.
|
|
186
|
+
|
|
187
|
+
**The confirmation gate (mandatory).** The draft is ready when it has a title,
|
|
188
|
+
a description following the template, at least one acceptance criterion, and
|
|
189
|
+
you have no outstanding question. Then — and only then — render the COMPLETE
|
|
190
|
+
final spec once (title, priority, labels, short summary, full description,
|
|
191
|
+
numbered acceptance criteria) and ask exactly one question: whether to create
|
|
192
|
+
it ("this is a normal write — no AI cost"). Do not call any persisting tool
|
|
193
|
+
until the user answers yes to that render. If they edit, update and re-render.
|
|
194
|
+
|
|
195
|
+
**Pausing.** There is no draft-ticket path for you (\`save_draft\` needs a real
|
|
196
|
+
app Explore conversation). If the user pauses, summarize the full draft state
|
|
197
|
+
in your reply so this conversation's history preserves it; resume from that
|
|
198
|
+
summary later.
|
|
199
|
+
|
|
200
|
+
## Persisting a spec you authored
|
|
201
|
+
|
|
202
|
+
- On yes, make ONE call: \`specrails_specs(action:'commit_draft', title,
|
|
203
|
+
description, acceptanceCriteria, priority, labels, shortSummary)\` — with NO
|
|
204
|
+
\`conversationId\` and NO \`draftTicketId\`. One write inserts the complete spec.
|
|
205
|
+
Edit level; no AI spawn.
|
|
206
|
+
- NEVER route a refined spec through \`create\` or \`generate\` — those re-generate
|
|
207
|
+
the content with a fresh AI pass and destroy the refinement.
|
|
208
|
+
- NEVER pass this conversation's id as \`conversationId\` — agent conversations
|
|
209
|
+
are not Explore conversations and it corrupts the ticket's origin linkage.
|
|
210
|
+
That field only accepts a project Explore-chat conversation id from
|
|
211
|
+
\`specrails_chat\`.
|
|
212
|
+
- \`from_prompt\` is a fallback only when the user wants a verbatim dump; it
|
|
213
|
+
cannot carry acceptance criteria or a short summary.
|
|
214
|
+
- For fields \`commit_draft\` does not carry (assignee, prerequisites, metadata),
|
|
215
|
+
follow with one \`specrails_specs(update)\`.
|
|
216
|
+
- After success, confirm with the new spec id verbatim and tell the user it is
|
|
217
|
+
now in the Backlog column of the Specs board. Contract Refine is not
|
|
218
|
+
available for agent-authored specs; offer to write a \`## Contract Layer\`
|
|
219
|
+
section yourself if they want one. Then you MAY offer — never start — the
|
|
220
|
+
next step: assigning it to a rail and launching.
|
|
221
|
+
|
|
222
|
+
## Running work & reporting progress
|
|
223
|
+
|
|
224
|
+
- Configure then launch: \`specrails_rails(set_tickets, railIndex, ticketIds)\` →
|
|
225
|
+
\`specrails_rails(launch, railIndex, mode, …)\`. Setting a profile and then
|
|
226
|
+
switching the rail's engine to codex/gemini silently drops the profile.
|
|
227
|
+
- Launch proposal shape: tickets (ids + titles), rail number, mode, engine and
|
|
228
|
+
model/profile, plus "runs for minutes and costs money". Wait for yes.
|
|
229
|
+
- \`specrails_rails(stop)\` kills the rail's process tree AND cancels its queued
|
|
230
|
+
jobs (autonomous level).
|
|
231
|
+
- \`specrails_jobs(spawn, command)\` bypasses rails to enqueue an arbitrary
|
|
232
|
+
slash-command job (e.g. \`/specrails:implement #5 --yes\`). Use rails for
|
|
233
|
+
normal implement flows; spawn for advanced one-offs.
|
|
234
|
+
- After a 202, report the returned jobId(s)/ids VERBATIM and tell the user they
|
|
235
|
+
can also watch live in the app (rail header, Job Detail page). Then follow
|
|
236
|
+
with \`specrails_watch\` — long rails outlive the default 120 s window, so size
|
|
237
|
+
\`untilMs\` up (max 600000); on \`{settled:false}\` say the job is still running
|
|
238
|
+
and either watch again or poll \`specrails_jobs(get)\`. Never claim completion
|
|
239
|
+
you have not verified from a terminal event or a job read.
|
|
240
|
+
- While watching, stay silent — do not post per-event narration.
|
|
241
|
+
- On settle, report in ONE message: outcome, what the pipeline did to the
|
|
242
|
+
spec's status (done / reverted to todo / done with the needs-review flag —
|
|
243
|
+
these are pipeline-managed; do not "fix" them yourself), duration, and cost —
|
|
244
|
+
prefix the cost with \`~\` when the provider reports an estimate
|
|
245
|
+
(codex/gemini). Offer the Analytics page for detail. On failure, report the
|
|
246
|
+
failure faithfully and offer the diagnostic export.
|
|
247
|
+
|
|
248
|
+
## Stance
|
|
249
|
+
|
|
250
|
+
Be concise and action-oriented. Confirm what you did with concrete references
|
|
251
|
+
(ids, names). Never fabricate results — report tool outputs faithfully,
|
|
252
|
+
including failures. Announce cost before spending; announce risk before
|
|
253
|
+
destroying.
|
|
254
|
+
|
|
255
|
+
## Formatting
|
|
256
|
+
|
|
257
|
+
Make replies easy to read: separate distinct ideas into short paragraphs with a
|
|
258
|
+
blank line between them (avoid one dense block of text), and use bullet lists
|
|
259
|
+
for enumerations. Give the conversation some breathing room.
|
|
260
|
+
|
|
261
|
+
## Adding a project
|
|
262
|
+
|
|
263
|
+
When the user has no projects yet, or asks to add one:
|
|
264
|
+
1. Explain the UI path: click "Add Project" (the + in the left sidebar), enter
|
|
265
|
+
the repo's folder path, pick an AI provider, then run setup.
|
|
266
|
+
2. Then OFFER to do it from here: ask for the repo folder path and which AI
|
|
267
|
+
providers to set up, then with their go-ahead call
|
|
268
|
+
\`specrails_setup(add_project, path, providers)\` (edit level) and a SINGLE
|
|
269
|
+
\`specrails_setup(install, projectId)\` (operate level) — one install
|
|
270
|
+
provisions ALL the chosen providers in one shot (do not install them one at
|
|
271
|
+
a time). Use \`specrails_setup(prerequisites)\` / \`available_providers\` first
|
|
272
|
+
to confirm the machine is ready.
|
|
273
|
+
|
|
274
|
+
Setup is QUICK-only (fast, offline). Do NOT offer, mention, or attempt a "full"
|
|
275
|
+
or "enrich" install — that flow is deprecated and not available through you.
|
|
276
|
+
`;
|
|
277
|
+
exports.OPERATOR_SYSTEM_PROMPT = `You are the Specrails operator agent, embedded inside the Specrails Desktop app; drive it on the user's behalf using the specrails_* MCP tools. Your full operator manual is the CLAUDE.md auto-loaded from your working directory — follow it. Non-negotiables: target a project with specrails_select_project or the projectId argument, and ask rather than guess when none is pinned; follow HTTP-202 actions with specrails_watch (projectId required) and never claim success from the acceptance alone — on timeout, poll the domain read (e.g. specrails_jobs get); respect the cumulative permission ladder observe / edit / operate / autonomous — if a tool is refused, name the level the user must Shift+Tab to, never work around it; when you have refined a spec with the user, persist it with specrails_specs commit_draft (no conversationId) — never route it through create/generate, which regenerate the content with AI; report tool outputs faithfully, including failures. Format replies for easy reading: short paragraphs separated by blank lines, bullet lists for enumerations. When asking the user to pick between concrete choices, end the reply with a fenced options code block containing a JSON array of the 2-6 choice labels (rendered as clickable chips); never use that block otherwise.`;
|
|
@@ -9,6 +9,27 @@ exports.addAgentMessage = addAgentMessage;
|
|
|
9
9
|
exports.listAgentMessages = listAgentMessages;
|
|
10
10
|
const crypto_1 = require("crypto");
|
|
11
11
|
const agent_tier_1 = require("./agent-tier");
|
|
12
|
+
function mapMessage(row) {
|
|
13
|
+
let ids = [];
|
|
14
|
+
if (row.attachment_ids) {
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(row.attachment_ids);
|
|
17
|
+
if (Array.isArray(parsed))
|
|
18
|
+
ids = parsed.filter((x) => typeof x === 'string');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
/* ignore malformed */
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
id: row.id,
|
|
26
|
+
conversation_id: row.conversation_id,
|
|
27
|
+
role: row.role,
|
|
28
|
+
content: row.content,
|
|
29
|
+
attachment_ids: ids,
|
|
30
|
+
created_at: row.created_at,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
12
33
|
function mapConversation(row) {
|
|
13
34
|
if (!row)
|
|
14
35
|
return undefined;
|
|
@@ -16,8 +37,8 @@ function mapConversation(row) {
|
|
|
16
37
|
}
|
|
17
38
|
function createAgentConversation(db, input = {}) {
|
|
18
39
|
const id = (0, crypto_1.randomUUID)();
|
|
19
|
-
db.prepare(`INSERT INTO agent_conversations (id, provider, model, pinned_project_id, tier_level)
|
|
20
|
-
VALUES (?, ?, ?, ?, ?)`).run(id, input.provider ?? 'claude', input.model ?? null, input.pinnedProjectId ?? null, input.tierLevel ?? 0);
|
|
40
|
+
db.prepare(`INSERT INTO agent_conversations (id, provider, model, pinned_project_id, tier_level, reasoning_effort)
|
|
41
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(id, input.provider ?? 'claude', input.model ?? null, input.pinnedProjectId ?? null, input.tierLevel ?? 0, input.reasoningEffort ?? null);
|
|
21
42
|
return getAgentConversation(db, id);
|
|
22
43
|
}
|
|
23
44
|
function getAgentConversation(db, id) {
|
|
@@ -47,13 +68,14 @@ function deleteAgentConversation(db, id) {
|
|
|
47
68
|
}
|
|
48
69
|
function addAgentMessage(db, input) {
|
|
49
70
|
const id = (0, crypto_1.randomUUID)();
|
|
50
|
-
|
|
71
|
+
const attachmentIds = input.attachmentIds && input.attachmentIds.length ? JSON.stringify(input.attachmentIds) : null;
|
|
72
|
+
db.prepare('INSERT INTO agent_messages (id, conversation_id, role, content, attachment_ids) VALUES (?, ?, ?, ?, ?)').run(id, input.conversationId, input.role, input.content, attachmentIds);
|
|
51
73
|
// Touch the parent so the list stays ordered by latest activity.
|
|
52
74
|
db.prepare("UPDATE agent_conversations SET updated_at = datetime('now') WHERE id = ?").run(input.conversationId);
|
|
53
|
-
return db.prepare('SELECT * FROM agent_messages WHERE id = ?').get(id);
|
|
75
|
+
return mapMessage(db.prepare('SELECT * FROM agent_messages WHERE id = ?').get(id));
|
|
54
76
|
}
|
|
55
77
|
function listAgentMessages(db, conversationId) {
|
|
56
78
|
return db
|
|
57
79
|
.prepare('SELECT * FROM agent_messages WHERE conversation_id = ? ORDER BY created_at ASC, rowid ASC')
|
|
58
|
-
.all(conversationId);
|
|
80
|
+
.all(conversationId).map(mapMessage);
|
|
59
81
|
}
|
|
@@ -302,6 +302,144 @@ class AttachmentManager {
|
|
|
302
302
|
}
|
|
303
303
|
return textBlocks;
|
|
304
304
|
}
|
|
305
|
+
// ── Agent-scoped attachments ──────────────────────────────────────────────
|
|
306
|
+
// App-global agent conversations have no project slug/ticket, so their
|
|
307
|
+
// attachments live under a distinct, conversation-keyed root
|
|
308
|
+
// `~/.specrails/agent/<conversationId>/attachments/` (never the project
|
|
309
|
+
// attachments root — that risks slug collisions and doesn't fit Home convos).
|
|
310
|
+
static AGENT_CONV_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
311
|
+
agentDir(conversationId) {
|
|
312
|
+
const key = String(conversationId);
|
|
313
|
+
if (key === '' || key === '.' || key === '..' || key !== path_1.default.basename(key) ||
|
|
314
|
+
key.includes('/') || key.includes('\\') || !AttachmentManager.AGENT_CONV_ID_RE.test(key)) {
|
|
315
|
+
throw new Error(`Invalid agent conversation id: ${JSON.stringify(key)}`);
|
|
316
|
+
}
|
|
317
|
+
return path_1.default.join(this.homeDir, '.specrails', 'agent', key, 'attachments');
|
|
318
|
+
}
|
|
319
|
+
agentSidecarPath(conversationId, attachmentId) {
|
|
320
|
+
this.assertValidAttachmentId(attachmentId);
|
|
321
|
+
return path_1.default.join(this.agentDir(conversationId), `${attachmentId}.meta.json`);
|
|
322
|
+
}
|
|
323
|
+
readAgentMeta(conversationId, attachmentId) {
|
|
324
|
+
const p = this.agentSidecarPath(conversationId, attachmentId);
|
|
325
|
+
if (!fs_1.default.existsSync(p))
|
|
326
|
+
return null;
|
|
327
|
+
try {
|
|
328
|
+
return JSON.parse(fs_1.default.readFileSync(p, 'utf-8'));
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async uploadAgent(opts) {
|
|
335
|
+
const normalizedMimeType = normalizeUploadedMimeType(opts.file.mimetype, opts.file.originalname);
|
|
336
|
+
if (!exports.SUPPORTED_MIME_TYPES.has(normalizedMimeType)) {
|
|
337
|
+
const err = new Error(`Unsupported file type: ${opts.file.mimetype}`);
|
|
338
|
+
err.status = 400;
|
|
339
|
+
throw err;
|
|
340
|
+
}
|
|
341
|
+
const id = (0, ids_1.newId)();
|
|
342
|
+
const storedName = `${id}-${sanitizeFilename(opts.file.originalname)}`;
|
|
343
|
+
const attachment = {
|
|
344
|
+
id,
|
|
345
|
+
filename: opts.file.originalname,
|
|
346
|
+
storedName,
|
|
347
|
+
mimeType: normalizedMimeType,
|
|
348
|
+
size: opts.file.size,
|
|
349
|
+
addedAt: new Date().toISOString(),
|
|
350
|
+
};
|
|
351
|
+
const dir = this.agentDir(opts.conversationId);
|
|
352
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
353
|
+
fs_1.default.writeFileSync(path_1.default.join(dir, storedName), opts.file.buffer);
|
|
354
|
+
fs_1.default.writeFileSync(this.agentSidecarPath(opts.conversationId, id), JSON.stringify(attachment, null, 2), 'utf-8');
|
|
355
|
+
return attachment;
|
|
356
|
+
}
|
|
357
|
+
listAgent(conversationId) {
|
|
358
|
+
let dir;
|
|
359
|
+
try {
|
|
360
|
+
dir = this.agentDir(conversationId);
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
if (!fs_1.default.existsSync(dir))
|
|
366
|
+
return [];
|
|
367
|
+
return fs_1.default
|
|
368
|
+
.readdirSync(dir)
|
|
369
|
+
.filter((f) => f.endsWith('.meta.json'))
|
|
370
|
+
.map((f) => {
|
|
371
|
+
try {
|
|
372
|
+
return JSON.parse(fs_1.default.readFileSync(path_1.default.join(dir, f), 'utf-8'));
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
.filter((m) => m !== null)
|
|
379
|
+
.sort((a, b) => (a.addedAt < b.addedAt ? 1 : -1));
|
|
380
|
+
}
|
|
381
|
+
getAgentMeta(conversationId, attachmentId) {
|
|
382
|
+
return this.readAgentMeta(conversationId, attachmentId);
|
|
383
|
+
}
|
|
384
|
+
getAgentFilePath(conversationId, attachmentId) {
|
|
385
|
+
const meta = this.readAgentMeta(conversationId, attachmentId);
|
|
386
|
+
if (!meta)
|
|
387
|
+
return null;
|
|
388
|
+
const abs = path_1.default.join(this.agentDir(conversationId), meta.storedName);
|
|
389
|
+
return fs_1.default.existsSync(abs) ? abs : null;
|
|
390
|
+
}
|
|
391
|
+
async deleteAgent(conversationId, attachmentId) {
|
|
392
|
+
const meta = this.readAgentMeta(conversationId, attachmentId);
|
|
393
|
+
if (!meta)
|
|
394
|
+
return false;
|
|
395
|
+
const dir = this.agentDir(conversationId);
|
|
396
|
+
const bin = path_1.default.join(dir, meta.storedName);
|
|
397
|
+
if (fs_1.default.existsSync(bin))
|
|
398
|
+
fs_1.default.unlinkSync(bin);
|
|
399
|
+
const side = this.agentSidecarPath(conversationId, attachmentId);
|
|
400
|
+
if (fs_1.default.existsSync(side))
|
|
401
|
+
fs_1.default.unlinkSync(side);
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
/** Remove the entire per-conversation agent directory (attachments + siblings). */
|
|
405
|
+
async deleteAllAgent(conversationId) {
|
|
406
|
+
// Validate the id (throws on traversal) then remove the parent conversation dir.
|
|
407
|
+
this.agentDir(conversationId);
|
|
408
|
+
const dir = path_1.default.join(this.homeDir, '.specrails', 'agent', String(conversationId));
|
|
409
|
+
if (fs_1.default.existsSync(dir))
|
|
410
|
+
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Agent variant of getClaudeArgs, keyed by conversation id. Returns extracted
|
|
414
|
+
* text blocks (all providers) AND absolute image paths (codex `--image`). The
|
|
415
|
+
* image `@<abs-path>` stays in textBlocks so claude resolves it and gemini gets
|
|
416
|
+
* a best-effort shot; `imagePaths` is additive and only codex consumes it.
|
|
417
|
+
*/
|
|
418
|
+
async getClaudeArgsAgent(conversationId, attachmentIds) {
|
|
419
|
+
const textBlocks = [];
|
|
420
|
+
const imagePaths = [];
|
|
421
|
+
for (const id of attachmentIds) {
|
|
422
|
+
const meta = this.readAgentMeta(conversationId, id);
|
|
423
|
+
if (!meta)
|
|
424
|
+
continue;
|
|
425
|
+
const abs = path_1.default.join(this.agentDir(conversationId), meta.storedName);
|
|
426
|
+
if (!fs_1.default.existsSync(abs))
|
|
427
|
+
continue;
|
|
428
|
+
if (meta.mimeType.startsWith(IMAGE_MIME_PREFIX)) {
|
|
429
|
+
imagePaths.push(abs);
|
|
430
|
+
textBlocks.push(wrapUserAttachment(meta, `@${abs}`));
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
const text = await extractText(abs, meta.mimeType);
|
|
435
|
+
textBlocks.push(wrapUserAttachment(meta, text));
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
textBlocks.push(wrapUserAttachment(meta, '[extraction failed]'));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return { textBlocks, imagePaths };
|
|
442
|
+
}
|
|
305
443
|
}
|
|
306
444
|
exports.AttachmentManager = AttachmentManager;
|
|
307
445
|
function wrapUserAttachment(meta, content) {
|
|
@@ -378,6 +378,18 @@ function applyDesktopMigrations(db) {
|
|
|
378
378
|
CREATE INDEX IF NOT EXISTS idx_agent_messages_conv ON agent_messages(conversation_id, created_at);
|
|
379
379
|
`);
|
|
380
380
|
},
|
|
381
|
+
// 18: persist the per-turn attachment id list on user messages so historical
|
|
382
|
+
// agent turns re-render pills/thumbnails after refresh (design D20). Nullable
|
|
383
|
+
// JSON array of attachment ids; NULL/absent = text-only turn (all old rows).
|
|
384
|
+
() => {
|
|
385
|
+
db.exec(`ALTER TABLE agent_messages ADD COLUMN attachment_ids TEXT;`);
|
|
386
|
+
},
|
|
387
|
+
// 19: per-conversation reasoning effort for agent spawns. NULL = the app
|
|
388
|
+
// default ("medium"); validated against the provider's effort catalog at the
|
|
389
|
+
// router (claude: low…xhigh, codex: minimal…high, gemini: none).
|
|
390
|
+
() => {
|
|
391
|
+
db.exec(`ALTER TABLE agent_conversations ADD COLUMN reasoning_effort TEXT;`);
|
|
392
|
+
},
|
|
381
393
|
];
|
|
382
394
|
for (let i = 0; i < migrations.length; i++) {
|
|
383
395
|
const version = i + 1;
|
|
@@ -444,6 +456,9 @@ function addProject(db, project) {
|
|
|
444
456
|
}
|
|
445
457
|
function removeProject(db, id) {
|
|
446
458
|
db.prepare('DELETE FROM projects WHERE id = ?').run(id);
|
|
459
|
+
// No FK on agent_conversations.pinned_project_id — unpin so orphaned agent
|
|
460
|
+
// conversations fold into Home instead of dangling on a dead project id.
|
|
461
|
+
db.prepare('UPDATE agent_conversations SET pinned_project_id = NULL WHERE pinned_project_id = ?').run(id);
|
|
447
462
|
}
|
|
448
463
|
function touchProject(db, id) {
|
|
449
464
|
db.prepare("UPDATE projects SET last_seen_at = datetime('now') WHERE id = ?").run(id);
|
|
@@ -31,12 +31,22 @@ exports.FACTORY_LOOPS = [
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
id: 'factory:ultracode',
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// Renamed from "Ultracode": the mode hands the spec straight to the model
|
|
35
|
+
// with full freedom — no pipeline, it works like a regular coding agent.
|
|
36
|
+
// The id/mode strings stay 'ultracode' (wire + rail back-compat).
|
|
37
|
+
name: 'Freestyle',
|
|
38
|
+
description: 'Hands the spec straight to the model with full freedom — no pipeline, it works like a regular coding agent, then verify + refine until green. Claude only.',
|
|
36
39
|
mode: 'ultracode',
|
|
37
40
|
claudeOnly: true,
|
|
38
41
|
graph: (0, loop_templates_1.fixLoopGraph)(['{{cmd:ultracode}}'], GREEN_GOAL, FACTORY_MAX_ITERATIONS, FACTORY_LOOP_TIMEOUT_MIN, FACTORY_AI_STEP_TIMEOUT_MIN),
|
|
39
42
|
},
|
|
43
|
+
{
|
|
44
|
+
id: 'factory:openspec',
|
|
45
|
+
name: 'OpenSpec Lifecycle',
|
|
46
|
+
description: 'Ticket-to-archive OpenSpec lifecycle: generate artifacts (opsx:ff) → implement (opsx:apply) → verify (opsx:verify); on FAIL loop back and amend the same change, on PASS archive it unattended.',
|
|
47
|
+
mode: 'loop',
|
|
48
|
+
graph: (0, loop_templates_1.opsxLifecycleGraph)(),
|
|
49
|
+
},
|
|
40
50
|
];
|
|
41
51
|
const FACTORY_BY_ID = new Map(exports.FACTORY_LOOPS.map((f) => [f.id, f]));
|
|
42
52
|
function getFactoryLoop(id) {
|