specrails-desktop 2.0.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/.claude/commands/specrails/batch-implement.md +287 -0
- package/.claude/commands/specrails/compat-check.md +271 -0
- package/.claude/commands/specrails/doctor.md +62 -0
- package/.claude/commands/specrails/enrich.md +1635 -0
- package/.claude/commands/specrails/explore-spec.md +173 -0
- package/.claude/commands/specrails/health-check.md +527 -0
- package/.claude/commands/specrails/implement.md +1457 -0
- package/.claude/commands/specrails/memory-inspect.md +259 -0
- package/.claude/commands/specrails/opsx-diff.md +419 -0
- package/.claude/commands/specrails/propose-spec.md +102 -0
- package/.claude/commands/specrails/reconfig.md +89 -0
- package/.claude/commands/specrails/refactor-recommender.md +212 -0
- package/.claude/commands/specrails/retry.md +363 -0
- package/.claude/commands/specrails/telemetry.md +552 -0
- package/.claude/commands/specrails/why.md +96 -0
- package/LICENSE +21 -0
- package/README.md +290 -0
- package/cli/dist/specrails-desktop.js +1098 -0
- package/client/dist/assets/ActivityFeedPage-Gy4x8dBt.js +1 -0
- package/client/dist/assets/AgentsPage-CPgu--Fb.js +86 -0
- package/client/dist/assets/AnalyticsPage-B5sJEee2.js +1 -0
- package/client/dist/assets/BarChart-7IMQ8HY1.js +33 -0
- package/client/dist/assets/CodePage-CBdFvbwe.js +2 -0
- package/client/dist/assets/DesktopAnalyticsPage-w0rdTq4w.js +1 -0
- package/client/dist/assets/DocsDialog-BZUYM7wm.js +11 -0
- package/client/dist/assets/DocsPage-9QglWl46.js +11 -0
- package/client/dist/assets/ExportDropdown-BLZFXtNi.js +1 -0
- package/client/dist/assets/IntegrationsPage-BxBE4y99.js +3 -0
- package/client/dist/assets/JobDetailPage-DydWx_5S.js +16 -0
- package/client/dist/assets/JobsPage-20ibw0IO.js +1 -0
- package/client/dist/assets/abap-Bw6f2wDG.js +1 -0
- package/client/dist/assets/activity-BEIp_Y1A.js +1 -0
- package/client/dist/assets/activity-BdrPln96.js +1 -0
- package/client/dist/assets/activity-CpkRS8Sx.js +1 -0
- package/client/dist/assets/activity-DKCpESPt.js +1 -0
- package/client/dist/assets/activity-DOUVEjJi.js +1 -0
- package/client/dist/assets/activity-DRwkql_y.js +1 -0
- package/client/dist/assets/activity-DcDQ7tjw.js +1 -0
- package/client/dist/assets/activity-Dv6H7wEr.js +1 -0
- package/client/dist/assets/addon-image-3WCl5Vhd.js +1 -0
- package/client/dist/assets/addon-ligatures-C5OdliKs.js +2 -0
- package/client/dist/assets/addon-webgl-BbX6pSjl.js +44 -0
- package/client/dist/assets/addspec-B5yl4Loj.js +1 -0
- package/client/dist/assets/addspec-BEeF5-zc.js +1 -0
- package/client/dist/assets/addspec-D33ocMxf.js +1 -0
- package/client/dist/assets/addspec-DFswZ0jK.js +1 -0
- package/client/dist/assets/addspec-DRE-jZv7.js +1 -0
- package/client/dist/assets/addspec-DVZ15Jp8.js +1 -0
- package/client/dist/assets/addspec-Fkv91Opc.js +1 -0
- package/client/dist/assets/addspec-GWm4ffKl.js +1 -0
- package/client/dist/assets/agents-1nCDWRmP.js +1 -0
- package/client/dist/assets/agents-Bm9rPqnt.js +1 -0
- package/client/dist/assets/agents-CMxtJMLD.js +1 -0
- package/client/dist/assets/agents-DK-Dlc0i.js +1 -0
- package/client/dist/assets/agents-Q6Ldfpxx.js +1 -0
- package/client/dist/assets/agents-TeOSy-ax.js +1 -0
- package/client/dist/assets/agents-iTqjRajS.js +1 -0
- package/client/dist/assets/agents-s87sMGzL.js +1 -0
- package/client/dist/assets/agentstudio-B6Wb59E7.js +1 -0
- package/client/dist/assets/agentstudio-BADhZ41e.js +1 -0
- package/client/dist/assets/agentstudio-BSnWLR63.js +1 -0
- package/client/dist/assets/agentstudio-BdidyBzZ.js +1 -0
- package/client/dist/assets/agentstudio-CxlUllqI.js +1 -0
- package/client/dist/assets/agentstudio-D3I62TLJ.js +1 -0
- package/client/dist/assets/agentstudio-DuH9TogZ.js +1 -0
- package/client/dist/assets/agentstudio-Kw88_dUF.js +1 -0
- package/client/dist/assets/aiedit-BWxHGsYA.js +1 -0
- package/client/dist/assets/aiedit-D2ji6Qy0.js +1 -0
- package/client/dist/assets/aiedit-DAhZTvtk.js +1 -0
- package/client/dist/assets/aiedit-DJMny-D5.js +1 -0
- package/client/dist/assets/aiedit-DOcxERkU.js +1 -0
- package/client/dist/assets/aiedit-DvrcbwGv.js +1 -0
- package/client/dist/assets/aiedit-TTwzL1TS.js +1 -0
- package/client/dist/assets/aiedit-WBSjT_C1.js +1 -0
- package/client/dist/assets/analytics-BIdr0YfL.js +1 -0
- package/client/dist/assets/analytics-C6EzgtdE.js +1 -0
- package/client/dist/assets/analytics-C9Zc-rkM.js +1 -0
- package/client/dist/assets/analytics-CVx3YOc0.js +1 -0
- package/client/dist/assets/analytics-CYj0tfj7.js +1 -0
- package/client/dist/assets/analytics-CnY4kNG3.js +1 -0
- package/client/dist/assets/analytics-CrPCZRJ-.js +1 -0
- package/client/dist/assets/analytics-DMCto-TF.js +1 -0
- package/client/dist/assets/apex-Cw8_REBo.js +1 -0
- package/client/dist/assets/atom-one-dark-B-oHczHB.css +1 -0
- package/client/dist/assets/attachments-BIsSSnHJ.js +1 -0
- package/client/dist/assets/attachments-BW4L3l2L.js +1 -0
- package/client/dist/assets/attachments-Bcf6BG6V.js +1 -0
- package/client/dist/assets/attachments-Bke8sCU4.js +1 -0
- package/client/dist/assets/attachments-COcrGRFz.js +1 -0
- package/client/dist/assets/attachments-DYHGA2Dj.js +1 -0
- package/client/dist/assets/attachments-Dd92KpUH.js +1 -0
- package/client/dist/assets/attachments-DzdU6DV6.js +1 -0
- package/client/dist/assets/azcli-Cz6HAoOw.js +1 -0
- package/client/dist/assets/bat-CcJ-xyqL.js +1 -0
- package/client/dist/assets/bicep-z1WDCKYz.js +2 -0
- package/client/dist/assets/browser-5ErDlJoR.js +1 -0
- package/client/dist/assets/browser-Bc-YdlVg.js +1 -0
- package/client/dist/assets/browser-BlYF4OOq.js +1 -0
- package/client/dist/assets/browser-CT-ReZGt.js +1 -0
- package/client/dist/assets/browser-DGITz3fC.js +1 -0
- package/client/dist/assets/browser-JsAIGCEW.js +1 -0
- package/client/dist/assets/browser-M5-rbPlw.js +1 -0
- package/client/dist/assets/browser-Qya9cARy.js +1 -0
- package/client/dist/assets/cameligo-BRewOpfa.js +1 -0
- package/client/dist/assets/chat-BEGuC03z.js +1 -0
- package/client/dist/assets/chat-BEW60P_u.js +1 -0
- package/client/dist/assets/chat-BQNMD0PL.js +1 -0
- package/client/dist/assets/chat-BsbNGPW9.js +1 -0
- package/client/dist/assets/chat-CboQguCi.js +1 -0
- package/client/dist/assets/chat-DRCa9pOt.js +1 -0
- package/client/dist/assets/chat-DwUm6W9z.js +1 -0
- package/client/dist/assets/chat-yoXwguQu.js +1 -0
- package/client/dist/assets/chunk-CilyBKbf.js +1 -0
- package/client/dist/assets/clojure-DBjRWN6g.js +1 -0
- package/client/dist/assets/clsx-DnqN-uhr.js +1 -0
- package/client/dist/assets/code-AL1rVIMb.js +1 -0
- package/client/dist/assets/code-C0BKpkht.js +1 -0
- package/client/dist/assets/code-C0FTS3ew.js +1 -0
- package/client/dist/assets/code-CPcHxzxw.js +1 -0
- package/client/dist/assets/code-D3ryDniw.js +1 -0
- package/client/dist/assets/code-D3zVVQTj.js +1 -0
- package/client/dist/assets/code-PCmfS3dn.js +1 -0
- package/client/dist/assets/code-exI0G5Wd.js +1 -0
- package/client/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/client/dist/assets/coffee-Cfk_XHGR.js +1 -0
- package/client/dist/assets/commands-B772IyDa.js +1 -0
- package/client/dist/assets/commands-BDDp6xFG.js +1 -0
- package/client/dist/assets/commands-CJxCry-o.js +1 -0
- package/client/dist/assets/commands-CfgY-_of.js +1 -0
- package/client/dist/assets/commands-DLrvnPNg.js +1 -0
- package/client/dist/assets/commands-IXMOKBYt.js +1 -0
- package/client/dist/assets/commands-UD1NzmwX.js +1 -0
- package/client/dist/assets/commands-sqrqsxyE.js +1 -0
- package/client/dist/assets/common-DCr6VzJ7.js +1 -0
- package/client/dist/assets/common-Dard9UNH.js +1 -0
- package/client/dist/assets/common-DeDELLZJ.js +1 -0
- package/client/dist/assets/common-DltqHaAe.js +1 -0
- package/client/dist/assets/common-Dmm1GhdD.js +1 -0
- package/client/dist/assets/common-DnjcgkPH.js +1 -0
- package/client/dist/assets/common-GbpxfPG8.js +1 -0
- package/client/dist/assets/common-wA36jmj1.js +1 -0
- package/client/dist/assets/cpp-BVob6BaP.js +1 -0
- package/client/dist/assets/csharp-C4fbRuOu.js +1 -0
- package/client/dist/assets/csp-DthFP_vT.js +1 -0
- package/client/dist/assets/css-CGMH0hcW.js +3 -0
- package/client/dist/assets/css.worker-Wv5dxAWO.js +89 -0
- package/client/dist/assets/cssMode-Cc6ozl-J.js +1 -0
- package/client/dist/assets/cypher-Pnf68BRV.js +1 -0
- package/client/dist/assets/dart-PMMOtxZX.js +1 -0
- package/client/dist/assets/dashboard-B4ixDVk8.js +1 -0
- package/client/dist/assets/dashboard-BZBADHSj.js +1 -0
- package/client/dist/assets/dashboard-C1MfeUHs.js +1 -0
- package/client/dist/assets/dashboard-C7SK6xu5.js +1 -0
- package/client/dist/assets/dashboard-CB6Le1yN.js +1 -0
- package/client/dist/assets/dashboard-CoTpMOBM.js +1 -0
- package/client/dist/assets/dashboard-Duo4DDCW.js +1 -0
- package/client/dist/assets/dashboard-I19DXBxw.js +1 -0
- package/client/dist/assets/dist-js-BY-Fv_fg.js +1 -0
- package/client/dist/assets/dist-js-Bakc4uxT.js +1 -0
- package/client/dist/assets/dockerfile-di1nsJCc.js +1 -0
- package/client/dist/assets/ecl-D_WVcB5M.js +1 -0
- package/client/dist/assets/editor-Br_kD0ds.css +1 -0
- package/client/dist/assets/editor.api2-XLGzZfbc.js +872 -0
- package/client/dist/assets/editor.main-CfXxHimg.js +6 -0
- package/client/dist/assets/editor.worker-Bd9IXS8d.js +26 -0
- package/client/dist/assets/elixir-OAdJEMOn.js +1 -0
- package/client/dist/assets/explore-4mFpnrKU.js +1 -0
- package/client/dist/assets/explore-A8Ltoblq.js +1 -0
- package/client/dist/assets/explore-B9A3iN2W.js +1 -0
- package/client/dist/assets/explore-BV5Xxlsn.js +1 -0
- package/client/dist/assets/explore-BrBJvfjP.js +1 -0
- package/client/dist/assets/explore-C3FSE42C.js +1 -0
- package/client/dist/assets/explore-D2EFgt8J.js +1 -0
- package/client/dist/assets/explore-hFc3HFcp.js +1 -0
- package/client/dist/assets/flow9-D3QEZjgn.js +1 -0
- package/client/dist/assets/format-command-CwGuwzGA.js +1 -0
- package/client/dist/assets/freemarker2-DP7J1gG3.js +3 -0
- package/client/dist/assets/fsharp-BF0k_8N8.js +1 -0
- package/client/dist/assets/go-BAQO5Jsz.js +1 -0
- package/client/dist/assets/graphql-hdFVFkiV.js +1 -0
- package/client/dist/assets/handlebars-BjRlucw6.js +1 -0
- package/client/dist/assets/hcl-DWnl1o-X.js +1 -0
- package/client/dist/assets/html-OumBQJ-U.js +1 -0
- package/client/dist/assets/html.worker-CQP8QQsS.js +502 -0
- package/client/dist/assets/htmlMode-CStc3zXM.js +1 -0
- package/client/dist/assets/index-CimDRRi7.css +2 -0
- package/client/dist/assets/index-XGZaKl_u.js +142 -0
- package/client/dist/assets/ini-CB-6OVu3.js +1 -0
- package/client/dist/assets/integrations-C3p12Ms6.js +1 -0
- package/client/dist/assets/integrations-Cr6hH7XR.js +1 -0
- package/client/dist/assets/integrations-Cublz3m6.js +1 -0
- package/client/dist/assets/integrations-D28q1kF6.js +1 -0
- package/client/dist/assets/integrations-DRdbki5W.js +1 -0
- package/client/dist/assets/integrations-DaC4SzzL.js +1 -0
- package/client/dist/assets/integrations-DmQYCUvN.js +1 -0
- package/client/dist/assets/integrations-HIlUxXVs.js +1 -0
- package/client/dist/assets/java-d1CmfiHX.js +1 -0
- package/client/dist/assets/javascript-CMk--e7g.js +1 -0
- package/client/dist/assets/jobs-BE1siB0M.js +1 -0
- package/client/dist/assets/jobs-BHcQ_Faf.js +1 -0
- package/client/dist/assets/jobs-CFfc2dNX.js +1 -0
- package/client/dist/assets/jobs-CSi5n8X_.js +1 -0
- package/client/dist/assets/jobs-Dc3X86PY.js +1 -0
- package/client/dist/assets/jobs-De5tASex.js +1 -0
- package/client/dist/assets/jobs-DsoXEdo7.js +1 -0
- package/client/dist/assets/jobs-Wl-ApPMb.js +1 -0
- package/client/dist/assets/json.worker-DzV-CpCQ.js +58 -0
- package/client/dist/assets/jsonMode-C2h3ZcjZ.js +7 -0
- package/client/dist/assets/julia-Bgv08lKa.js +1 -0
- package/client/dist/assets/kotlin-u98kaVTf.js +1 -0
- package/client/dist/assets/less-CjYwpgg5.js +2 -0
- package/client/dist/assets/lexon-YTjaAFBB.js +1 -0
- package/client/dist/assets/lib-CPxTMOAq.js +7 -0
- package/client/dist/assets/liquid-mI3KJrBE.js +1 -0
- package/client/dist/assets/lspLanguageFeatures-DU09ggWi.js +4 -0
- package/client/dist/assets/lua-BzmkWv27.js +1 -0
- package/client/dist/assets/m3-CFwk9fw0.js +1 -0
- package/client/dist/assets/markdown-CR5iMpSZ.js +1 -0
- package/client/dist/assets/mdx-C41VDTR_.js +1 -0
- package/client/dist/assets/mips-CcEalc17.js +1 -0
- package/client/dist/assets/monaco.contribution-CPObAXMC.js +2 -0
- package/client/dist/assets/msdax-BQbkawnr.js +1 -0
- package/client/dist/assets/mysql-GTlaaW_P.js +1 -0
- package/client/dist/assets/nav-0fwkrgHt.js +1 -0
- package/client/dist/assets/nav-BEL3MTwK.js +1 -0
- package/client/dist/assets/nav-B_G-TJDW.js +1 -0
- package/client/dist/assets/nav-C2YXcbZS.js +1 -0
- package/client/dist/assets/nav-ClzOE4mA.js +1 -0
- package/client/dist/assets/nav-CtYwmMgu.js +1 -0
- package/client/dist/assets/nav-D2bOGSEg.js +1 -0
- package/client/dist/assets/nav-iH1V5j6o.js +1 -0
- package/client/dist/assets/objective-c-Byu1T5if.js +1 -0
- package/client/dist/assets/pascal-BrfzBfRm.js +1 -0
- package/client/dist/assets/pascaligo-BXXKFUeo.js +1 -0
- package/client/dist/assets/perl-B3OikKq-.js +1 -0
- package/client/dist/assets/pgsql-CTsa0Acc.js +1 -0
- package/client/dist/assets/php-DiQh3FUW.js +1 -0
- package/client/dist/assets/pla-92uH8Fzm.js +1 -0
- package/client/dist/assets/postiats-BbeWkKUr.js +1 -0
- package/client/dist/assets/powerquery-DgDMzpsm.js +1 -0
- package/client/dist/assets/powershell-BfdUUzaG.js +1 -0
- package/client/dist/assets/preload-helper-DSXbuxSR.js +1 -0
- package/client/dist/assets/protobuf-BojW2ftW.js +2 -0
- package/client/dist/assets/pug-BxqTg3IU.js +1 -0
- package/client/dist/assets/python-Y27rKQtk.js +1 -0
- package/client/dist/assets/qsharp-BX_A-MW9.js +1 -0
- package/client/dist/assets/r-D9BMnxvJ.js +1 -0
- package/client/dist/assets/razor-Cd5-q9Bp.js +1 -0
- package/client/dist/assets/redis-5cJqEQJJ.js +1 -0
- package/client/dist/assets/redshift-d8BBqiwb.js +1 -0
- package/client/dist/assets/restructuredtext-C8a6yIcZ.js +1 -0
- package/client/dist/assets/ruby-egeh-6KX.js +1 -0
- package/client/dist/assets/rust-a3r9IInB.js +1 -0
- package/client/dist/assets/sb-y8iRIDei.js +1 -0
- package/client/dist/assets/scala-BPDK2AmK.js +1 -0
- package/client/dist/assets/scheme-BIWUEoOs.js +1 -0
- package/client/dist/assets/scss-CA-PSzwg.js +3 -0
- package/client/dist/assets/settings-55oDcbSh.js +1 -0
- package/client/dist/assets/settings-Bd4Tq1RB.js +1 -0
- package/client/dist/assets/settings-CCSM-Fhn.js +1 -0
- package/client/dist/assets/settings-D3e_bDoW.js +1 -0
- package/client/dist/assets/settings-DKbTkbn7.js +1 -0
- package/client/dist/assets/settings-Dxpo6_w7.js +1 -0
- package/client/dist/assets/settings-bt84e3Aa.js +1 -0
- package/client/dist/assets/settings-nu68QukM.js +1 -0
- package/client/dist/assets/setup-BMqwfbW9.js +1 -0
- package/client/dist/assets/setup-Bb5LcG28.js +1 -0
- package/client/dist/assets/setup-BeEx2_da.js +1 -0
- package/client/dist/assets/setup-CCCrB53Q.js +1 -0
- package/client/dist/assets/setup-CJA0ATmd.js +1 -0
- package/client/dist/assets/setup-CeiDbZcb.js +1 -0
- package/client/dist/assets/setup-Cus7TApA.js +1 -0
- package/client/dist/assets/setup-D9qOs2Xo.js +1 -0
- package/client/dist/assets/shell--LiT1Bja.js +1 -0
- package/client/dist/assets/solidity-DdqZccZg.js +1 -0
- package/client/dist/assets/sophia-S6-YxNG_.js +1 -0
- package/client/dist/assets/sparql-BSf5kMp2.js +1 -0
- package/client/dist/assets/specs-BFfu3u-a.js +1 -0
- package/client/dist/assets/specs-B__C8-8a.js +1 -0
- package/client/dist/assets/specs-CZ1PsXsC.js +1 -0
- package/client/dist/assets/specs-D2FzlLn9.js +1 -0
- package/client/dist/assets/specs-DaUTrNF9.js +1 -0
- package/client/dist/assets/specs-Dyc5hYeE.js +1 -0
- package/client/dist/assets/specs-cKEh2LXt.js +1 -0
- package/client/dist/assets/specs-k0PyLDVt.js +1 -0
- package/client/dist/assets/sql-D7KgjR8G.js +1 -0
- package/client/dist/assets/st-BnoDa-Ml.js +1 -0
- package/client/dist/assets/swift-DEUHTkUX.js +1 -0
- package/client/dist/assets/systemverilog-Tqb_KPnW.js +1 -0
- package/client/dist/assets/tcl-BmBFS2qq.js +1 -0
- package/client/dist/assets/terminal-80yDMgMF.js +1 -0
- package/client/dist/assets/terminal-Bje4ziIa.js +1 -0
- package/client/dist/assets/terminal-C2WYcFHF.js +1 -0
- package/client/dist/assets/terminal-CSONJOex.js +1 -0
- package/client/dist/assets/terminal-DEqzGtcr.js +1 -0
- package/client/dist/assets/terminal-DeWzh6ys.js +1 -0
- package/client/dist/assets/terminal-YOlsJCQj.js +1 -0
- package/client/dist/assets/terminal-lkZYR4wJ.js +1 -0
- package/client/dist/assets/tickets-CB7N30gm.js +1 -0
- package/client/dist/assets/tickets-CF2PYelu.js +1 -0
- package/client/dist/assets/tickets-DNOANUXr.js +1 -0
- package/client/dist/assets/tickets-DU1aqsbr.js +1 -0
- package/client/dist/assets/tickets-DYvafSaY.js +1 -0
- package/client/dist/assets/tickets-DlpC_iTg.js +1 -0
- package/client/dist/assets/tickets-DucYgtdl.js +1 -0
- package/client/dist/assets/tickets-clefmXLv.js +1 -0
- package/client/dist/assets/ts.worker-METxwbDZ.js +67719 -0
- package/client/dist/assets/tsMode-B0y_xEci.js +11 -0
- package/client/dist/assets/twig-BQV8igWC.js +1 -0
- package/client/dist/assets/typescript-BzK0OgwW.js +1 -0
- package/client/dist/assets/typespec-DlFroUGY.js +1 -0
- package/client/dist/assets/useProjectCache-DSaiGFjV.js +1 -0
- package/client/dist/assets/vb-BlrJpIMX.js +1 -0
- package/client/dist/assets/wgsl-BWgIc6FZ.js +298 -0
- package/client/dist/assets/workers-rt--R2Qy.js +1 -0
- package/client/dist/assets/xml-eX9QXAmI.js +1 -0
- package/client/dist/assets/yaml-fcsNkpOt.js +1 -0
- package/client/dist/index.html +246 -0
- package/docs/README.md +54 -0
- package/docs/cli.md +198 -0
- package/docs/codex.md +210 -0
- package/docs/creating-specs.md +197 -0
- package/docs/customizing.md +197 -0
- package/docs/getting-started.md +140 -0
- package/docs/internals/README.md +25 -0
- package/docs/internals/adding-a-provider.md +238 -0
- package/docs/internals/api-reference.md +634 -0
- package/docs/internals/architecture.md +332 -0
- package/docs/internals/configuration.md +172 -0
- package/docs/internals/openspec-workflow.md +282 -0
- package/docs/internals/operations-runbook.md +198 -0
- package/docs/internals/profiles.md +152 -0
- package/docs/platforms/macos.md +130 -0
- package/docs/platforms/windows.md +81 -0
- package/docs/running-pipelines.md +240 -0
- package/docs/terminal.md +138 -0
- package/docs/tracking-cost.md +155 -0
- package/package.json +82 -0
- package/server/dist/agent-generator.js +232 -0
- package/server/dist/agent-refine-db.js +124 -0
- package/server/dist/agent-refine-manager.js +526 -0
- package/server/dist/ai-invocations.js +111 -0
- package/server/dist/attachment-manager.js +299 -0
- package/server/dist/auth.js +207 -0
- package/server/dist/binary-probe.js +35 -0
- package/server/dist/browser-capture-manager.js +576 -0
- package/server/dist/browser-capture-types.js +28 -0
- package/server/dist/browser-network.js +149 -0
- package/server/dist/browser-playwright.js +888 -0
- package/server/dist/build-dirs.js +44 -0
- package/server/dist/changes-reader.js +120 -0
- package/server/dist/chat-manager.js +1060 -0
- package/server/dist/chromium-resolver.js +311 -0
- package/server/dist/code-explorer-router.js +788 -0
- package/server/dist/codex-otel-bridge.js +235 -0
- package/server/dist/command-resolver.js +102 -0
- package/server/dist/config.js +306 -0
- package/server/dist/context-budget.js +113 -0
- package/server/dist/context-scope.js +279 -0
- package/server/dist/contract-refine-runner.js +521 -0
- package/server/dist/core-compat.js +207 -0
- package/server/dist/core-package.js +14 -0
- package/server/dist/db.js +1034 -0
- package/server/dist/desktop-analytics.js +156 -0
- package/server/dist/desktop-db.js +456 -0
- package/server/dist/desktop-router.js +735 -0
- package/server/dist/docs-router.js +207 -0
- package/server/dist/explore-contract-refine.js +421 -0
- package/server/dist/explore-cwd-manager.js +242 -0
- package/server/dist/explore-draft-title.js +47 -0
- package/server/dist/explore-smash.js +450 -0
- package/server/dist/feature-flags.js +17 -0
- package/server/dist/file-provenance.js +382 -0
- package/server/dist/file-summary-generator.js +221 -0
- package/server/dist/file-summary-manager.js +689 -0
- package/server/dist/hooks.js +102 -0
- package/server/dist/ids.js +7 -0
- package/server/dist/index.js +586 -0
- package/server/dist/metrics.js +136 -0
- package/server/dist/mobile/index.js +16 -0
- package/server/dist/mobile/mobile-admin-router.js +84 -0
- package/server/dist/mobile/mobile-auth.js +67 -0
- package/server/dist/mobile/mobile-devices.js +80 -0
- package/server/dist/mobile/mobile-event-bus.js +39 -0
- package/server/dist/mobile/mobile-gateway.js +285 -0
- package/server/dist/mobile/mobile-mdns.js +81 -0
- package/server/dist/mobile/mobile-pairing.js +179 -0
- package/server/dist/mobile/mobile-redact.js +53 -0
- package/server/dist/mobile/mobile-router.js +411 -0
- package/server/dist/mobile/mobile-tls.js +86 -0
- package/server/dist/mobile/mobile-types.js +9 -0
- package/server/dist/mobile/mobile-ws.js +275 -0
- package/server/dist/path-resolver.js +298 -0
- package/server/dist/plugin-manager.js +617 -0
- package/server/dist/plugins/claude-approval.js +179 -0
- package/server/dist/plugins/claude-md-mutation.js +146 -0
- package/server/dist/plugins/codex-mcp.js +108 -0
- package/server/dist/plugins/contributors.js +72 -0
- package/server/dist/plugins/drift.js +58 -0
- package/server/dist/plugins/index.js +14 -0
- package/server/dist/plugins/json-mutation.js +120 -0
- package/server/dist/plugins/manager.js +32 -0
- package/server/dist/plugins/ownership.js +86 -0
- package/server/dist/plugins/paths.js +37 -0
- package/server/dist/plugins/prereq-installer.js +104 -0
- package/server/dist/plugins/rail-integration.js +79 -0
- package/server/dist/plugins/serena/index.js +13 -0
- package/server/dist/plugins/serena/install.js +91 -0
- package/server/dist/plugins/serena/instructions-content.js +21 -0
- package/server/dist/plugins/serena/manifest.js +111 -0
- package/server/dist/plugins/serena/verify.js +78 -0
- package/server/dist/plugins-router.js +215 -0
- package/server/dist/pricing.js +89 -0
- package/server/dist/profile-manager.js +310 -0
- package/server/dist/profiles-router.js +759 -0
- package/server/dist/project-registry.js +443 -0
- package/server/dist/project-router.js +4016 -0
- package/server/dist/proposal-manager.js +291 -0
- package/server/dist/provider-selection.js +69 -0
- package/server/dist/providers/claude-adapter.js +281 -0
- package/server/dist/providers/codex-adapter.js +264 -0
- package/server/dist/providers/index.js +23 -0
- package/server/dist/providers/registry.js +37 -0
- package/server/dist/providers/types.js +22 -0
- package/server/dist/queue-manager.js +1511 -0
- package/server/dist/rails-router.js +362 -0
- package/server/dist/rails-store.js +116 -0
- package/server/dist/result-event.js +106 -0
- package/server/dist/schemas/profile.v1.json +151 -0
- package/server/dist/setup-manager.js +1165 -0
- package/server/dist/setup-prerequisites.js +372 -0
- package/server/dist/smash-runner.js +663 -0
- package/server/dist/spec-draft-parser.js +133 -0
- package/server/dist/spec-launcher-manager.js +174 -0
- package/server/dist/spec-models.js +32 -0
- package/server/dist/specrails-tech-client.js +82 -0
- package/server/dist/spending.js +448 -0
- package/server/dist/telemetry-compactor.js +180 -0
- package/server/dist/telemetry-export.js +317 -0
- package/server/dist/telemetry-receiver.js +224 -0
- package/server/dist/terminal-manager.js +633 -0
- package/server/dist/terminal-marks-store.js +117 -0
- package/server/dist/terminal-osc-parser.js +159 -0
- package/server/dist/terminal-settings.js +282 -0
- package/server/dist/terminal-shell-integration.js +196 -0
- package/server/dist/ticket-broadcast.js +47 -0
- package/server/dist/ticket-store.js +397 -0
- package/server/dist/ticket-watcher.js +117 -0
- package/server/dist/types.js +10 -0
- package/server/dist/user-mcp-config.js +117 -0
- package/server/dist/util/cli-prompt.js +181 -0
- package/server/dist/util/secure-fs.js +50 -0
- package/server/dist/util/win-spawn.js +43 -0
- package/server/dist/webhook-manager.js +89 -0
- package/server/dist/ws-routing.js +47 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This document describes the technical architecture of specrails-desktop (v1.63.1): its layers, data layout, request flow, authentication, and the subsystems that make up the app. It is the entry point to the other internals docs — see the [See also](#see-also) block at the bottom.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Three-layer monorepo
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
specrails-desktop/
|
|
11
|
+
├── server/ → Express 5 + WebSocket + SQLite (TypeScript, CommonJS)
|
|
12
|
+
├── client/ → React 19 + Vite + Tailwind v4 (TypeScript, ESM)
|
|
13
|
+
├── cli/ → specrails-desktop CLI bridge (TypeScript, CommonJS)
|
|
14
|
+
└── src-tauri/ → Tauri v2 desktop shell (Rust + bundled server sidecar)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Server and CLI compile to **CommonJS** (root `tsconfig.json`). The client is **ESM** with its own `client/tsconfig.json`. The client has its own `package.json` and `node_modules`, so two separate `npm install` calls are required (root + `client/`).
|
|
18
|
+
|
|
19
|
+
The server persists with **better-sqlite3** (synchronous SQLite) and serves over **Express 5**; the WebSocket layer uses **ws**.
|
|
20
|
+
|
|
21
|
+
### Everyday commands
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run dev # server (4200) + client (4201) concurrently
|
|
25
|
+
npm run dev:server # server only (tsx watch)
|
|
26
|
+
npm run dev:client # Vite dev client only
|
|
27
|
+
npm run build # production build: server → client → CLI
|
|
28
|
+
npm run typecheck # tsc --noEmit for server and client
|
|
29
|
+
npm test # vitest (server + CLI) + core-compat check
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Tests use vitest with `:memory:` SQLite databases.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Data layout
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
~/.specrails/
|
|
40
|
+
desktop.sqlite # project registry (id, name, path, slug, provider…)
|
|
41
|
+
desktop.token # auth token, mode 0600 (auto-generated on first run)
|
|
42
|
+
manager.pid # server PID for clean shutdown
|
|
43
|
+
projects/
|
|
44
|
+
<slug>/
|
|
45
|
+
jobs.sqlite # per-project: jobs, rails, tickets, invocations, …
|
|
46
|
+
jobs/<jobId>/ # per-job snapshots (profile.json, plugins.json, …)
|
|
47
|
+
telemetry/ # OTEL blobs (compacted after 7 days)
|
|
48
|
+
explore-cwd/ # app-managed Explore spawn cwd (CLAUDE.md + ./project link)
|
|
49
|
+
terminals/ # per-session shell-integration shims
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The app SQLite (`desktop.sqlite`) stores only project metadata. All per-project data lives in an isolated `jobs.sqlite` under the project's slug directory — not just jobs and chat, but rails, tickets, agent profiles/versions, AI invocations (cost analytics), telemetry pointers, file provenance, terminal settings/marks, and more (see the `MIGRATIONS` array in `server/db.ts`). Projects can be removed and re-added without losing history, and the registry can be wiped without touching project data.
|
|
53
|
+
|
|
54
|
+
> The data root is hardcoded to `os.homedir()/.specrails`. There is no environment override for the data directory.
|
|
55
|
+
>
|
|
56
|
+
> **Rebrand migration:** installs upgraded from the Specrails Hub era are migrated automatically — on startup the server renames a legacy `hub.sqlite` (plus its `-wal`/`-shm` sidecars) to `desktop.sqlite` and a legacy `hub.token` to `desktop.token` before opening them, so no data or token is lost.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Super-mode architecture
|
|
61
|
+
|
|
62
|
+
Super mode is the **only** supported mode — a single Express process manages every registered project. There is no legacy single-project runtime, and no mode detection.
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
┌─────────────────────────────────────────────────────┐
|
|
66
|
+
│ Express Server (port 4200, 127.0.0.1 only) │
|
|
67
|
+
│ │
|
|
68
|
+
│ ProjectRegistry │
|
|
69
|
+
│ ├── Project A → ProjectContext { db, queue, chat, │
|
|
70
|
+
│ ├── Project B → chatManager, setupManager, cwd } │
|
|
71
|
+
│ └── Project C → … │
|
|
72
|
+
│ │
|
|
73
|
+
│ Routes: │
|
|
74
|
+
│ /api/* → app-level operations │
|
|
75
|
+
│ /api/projects/:id/* → project-scoped actions │
|
|
76
|
+
│ /otlp/v1/* → OTLP telemetry receiver │
|
|
77
|
+
└─────────────────────────────────────────────────────┘
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Per-project isolation
|
|
81
|
+
|
|
82
|
+
Each project in the `ProjectRegistry` gets its own `ProjectContext`:
|
|
83
|
+
|
|
84
|
+
| Resource | Description |
|
|
85
|
+
|----------|-------------|
|
|
86
|
+
| `db` | SQLite connection to `projects/<slug>/jobs.sqlite` |
|
|
87
|
+
| `QueueManager` | Serialized job queue for this project (one active job at a time) |
|
|
88
|
+
| `ChatManager` | Isolated conversation manager (Explore + sidebar chat) |
|
|
89
|
+
| `SetupManager` | Wizard state for projects being onboarded |
|
|
90
|
+
| `cwd` | Absolute path to the project directory on disk |
|
|
91
|
+
|
|
92
|
+
The `boundBroadcast` closure injects `projectId` into all WebSocket messages, so managers don't need per-project constructor arguments.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Key server modules
|
|
97
|
+
|
|
98
|
+
| Module | Responsibility |
|
|
99
|
+
|--------|---------------|
|
|
100
|
+
| `index.ts` | Entry point: PATH resolution, auth bootstrap, port binding, router mounts, WS server |
|
|
101
|
+
| `auth.ts` | Token bootstrap + `requireAuth` middleware + WS upgrade token check |
|
|
102
|
+
| `desktop-db.ts` | App-level SQLite: project registry CRUD, app settings |
|
|
103
|
+
| `project-registry.ts` | `ProjectRegistry` class: load/unload per-project `ProjectContext` |
|
|
104
|
+
| `desktop-router.ts` | `/api/*` routes: projects, settings, themes, specrails-tech proxy, cross-project analytics |
|
|
105
|
+
| `project-router.ts` | `/api/projects/:id/*` routes: all project-scoped operations |
|
|
106
|
+
| `db.ts` | Per-project SQLite: schema (`MIGRATIONS`) + queries |
|
|
107
|
+
| `queue-manager.ts` | Job queue: spawn provider CLI processes serially per project |
|
|
108
|
+
| `chat-manager.ts` | Chat/Explore: spawn provider CLI for conversational turns |
|
|
109
|
+
| `setup-manager.ts` | Setup wizard: orchestrate `specrails-core` install + `/setup` chat |
|
|
110
|
+
| `config.ts` | Command discovery: scan `<project>/.claude/commands/sr/*.md` |
|
|
111
|
+
| `hooks.ts` | Pipeline event handler: process phase transition events |
|
|
112
|
+
| `spending.ts` | Cost/analytics aggregation (single source of truth) |
|
|
113
|
+
| `ai-invocations.ts` | `recordInvocation` — writes one billable row per AI CLI call |
|
|
114
|
+
| `pricing.ts` | Rate-card cost fallback for providers without native billing |
|
|
115
|
+
| `result-event.ts` | `finaliseInvocationResult` — combines adapter result + pricing |
|
|
116
|
+
| `telemetry-receiver.ts` | OTLP/JSON receiver mounted at `/otlp` |
|
|
117
|
+
| `desktop-analytics.ts` | App-level analytics aggregated across all projects |
|
|
118
|
+
| `metrics.ts` | Per-project health metrics |
|
|
119
|
+
| `docs-router.ts` | Serve the embedded docs portal (`/api/docs`) |
|
|
120
|
+
| `path-resolver.ts` | Resolve a usable PATH for GUI-launched desktop spawns |
|
|
121
|
+
| `types.ts` | Shared TypeScript interfaces |
|
|
122
|
+
|
|
123
|
+
Provider, terminal, profile, plugin, code-explorer, and explore subsystems each live in their own modules — see [Feature subsystems](#feature-subsystems).
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Client architecture
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
client/src/
|
|
131
|
+
├── App.tsx # Mounts DesktopProvider + DesktopApp unconditionally
|
|
132
|
+
├── components/
|
|
133
|
+
│ ├── TabBar.tsx # Project tab switcher
|
|
134
|
+
│ ├── ProjectLayout.tsx # Per-project three-panel wrapper
|
|
135
|
+
│ ├── ProjectNavbar.tsx # Left/right sidebar pin + collapse toggles
|
|
136
|
+
│ ├── ArcSidebar.tsx # Collapsible Arc-style left sidebar
|
|
137
|
+
│ ├── ProjectRightSidebar.tsx # Project nav (Jobs, Analytics, Agents, Code, …)
|
|
138
|
+
│ ├── TitleBar.tsx # Custom frameless titlebar (desktop)
|
|
139
|
+
│ ├── CommandGrid.tsx # Command launcher
|
|
140
|
+
│ ├── RecentJobs.tsx # Job history card list
|
|
141
|
+
│ ├── ProjectHealthWidget.tsx # Per-project health indicators
|
|
142
|
+
│ ├── AddProjectDialog.tsx # Register project modal (provider multi-select)
|
|
143
|
+
│ ├── WelcomeScreen.tsx # Zero-state landing
|
|
144
|
+
│ └── SetupWizard.tsx # Configure / Install / Done onboarding wizard
|
|
145
|
+
├── hooks/
|
|
146
|
+
│ ├── useDesktop.tsx # DesktopProvider context: project list, active project
|
|
147
|
+
│ ├── useProjectCache.ts # Stale-while-revalidate per-project cache
|
|
148
|
+
│ ├── useSpecGenTracker.tsx # Quick-spec generation state (localStorage)
|
|
149
|
+
│ ├── usePipeline.ts # Pipeline phase state
|
|
150
|
+
│ └── useSharedWebSocket.tsx # Single WS connection, per-project filtering
|
|
151
|
+
├── pages/
|
|
152
|
+
│ ├── DashboardPage.tsx # Specs board + Rails board + pipeline state
|
|
153
|
+
│ ├── AnalyticsPage.tsx # Per-project cost analytics
|
|
154
|
+
│ ├── DesktopAnalyticsPage.tsx # Cross-project spending roll-up
|
|
155
|
+
│ ├── AgentsPage.tsx # Agent profiles + catalog
|
|
156
|
+
│ ├── CodePage.tsx # Read-only code explorer (flag-gated)
|
|
157
|
+
│ ├── SettingsPage.tsx # Per-project settings
|
|
158
|
+
│ ├── GlobalSettingsPage.tsx # App settings
|
|
159
|
+
│ └── JobDetailPage.tsx # Full log viewer for a single job
|
|
160
|
+
└── lib/
|
|
161
|
+
├── api.ts # getApiBase(): dynamic API prefix per active project
|
|
162
|
+
├── pending-specs.ts # Quick-spec state persistence (localStorage)
|
|
163
|
+
└── route-memory.ts # Per-project URL route save/restore
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### App bootstrap
|
|
167
|
+
|
|
168
|
+
`App.tsx` mounts `DesktopProvider` and `<DesktopApp />` **unconditionally** — there is no mode detection and no fallback layout. The client fetches its auth token same-origin from `/api/token` and then loads the project registry.
|
|
169
|
+
|
|
170
|
+
### API base routing
|
|
171
|
+
|
|
172
|
+
`getApiBase()` (from `lib/api.ts`) always returns `${API_ORIGIN}/api/projects/<activeProjectId>` and **throws** when no active project is set — it never returns a bare `/api`. `DesktopProvider` updates the active project (via `setActiveProjectId`) on project switch; all API calls must go through `getApiBase()` rather than hardcoding `/api/projects/...`.
|
|
173
|
+
|
|
174
|
+
### Per-project tab switch pattern
|
|
175
|
+
|
|
176
|
+
On project switch:
|
|
177
|
+
1. `useDesktop` updates `activeProjectId`.
|
|
178
|
+
2. `useProjectCache` returns cached data immediately (no flicker).
|
|
179
|
+
3. A background fetch refreshes the cache for the new project.
|
|
180
|
+
4. Never reset to empty state — always show the last-known data while loading.
|
|
181
|
+
|
|
182
|
+
State-bearing hooks key off `activeProjectId` as a `useEffect` dependency. `useSpecGenTracker` (via `lib/pending-specs.ts`) and `lib/route-memory.ts` persist Quick-spec progress and the active URL route per project to `localStorage`, surviving refreshes and project switches.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Authentication
|
|
187
|
+
|
|
188
|
+
The app is local-first but **always authenticated** — auth is mandatory, not optional.
|
|
189
|
+
|
|
190
|
+
- On first run the server generates a token (two concatenated `randomUUID()`s) and persists it to `~/.specrails/desktop.token` with mode `0600` (`server/auth.ts`).
|
|
191
|
+
- `app.use('/api', requireAuth)` protects every `/api/*` route. The exceptions are `GET /api/health` and `GET /api/token` (both mounted before the middleware), plus `/api/docs` (the docs portal handlers respond before the auth fallthrough).
|
|
192
|
+
- `requireAuth` accepts the token as an `Authorization: Bearer <token>` header **or** an `X-Desktop-Token: <token>` header.
|
|
193
|
+
- WebSocket upgrades are authorized by `authorizeUpgrade`: the browser client sends the token as a subprotocol `desktop-token.<token>`; the CLI can pass it as a `Bearer` header.
|
|
194
|
+
|
|
195
|
+
There is no UI to set or clear the token and it is not an app setting. The browser client fetches it same-origin from `/api/token`, which is why that one route is public.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## WebSocket protocol
|
|
200
|
+
|
|
201
|
+
A single WebSocket connection at `ws://127.0.0.1:4200/ws` multiplexes all application messages. Terminal PTY output flows over a dedicated `/ws/terminal/:id` socket so high-throughput terminal data cannot starve the event stream.
|
|
202
|
+
|
|
203
|
+
Every project-scoped message includes a `projectId` field; app-level messages (`desktop.project_added`, `desktop.project_removed`, `desktop.projects`) have none.
|
|
204
|
+
|
|
205
|
+
### Representative message types
|
|
206
|
+
|
|
207
|
+
Canonical shapes live in `server/types.ts`. The core dashboard messages:
|
|
208
|
+
|
|
209
|
+
| Type | Scope | Payload (key fields) |
|
|
210
|
+
|------|-------|----------------------|
|
|
211
|
+
| `init` | project | `{ projectName, phases, phaseDefinitions, logBuffer, recentJobs, queue, projectId }` — per-connection dashboard snapshot sent on (re)connect |
|
|
212
|
+
| `queue` | project | `{ jobs, activeJobId, paused, timestamp, projectId }` — full queue snapshot |
|
|
213
|
+
| `log` | project | `{ source: 'stdout'\|'stderr', line, timestamp, processId, projectId }` |
|
|
214
|
+
| `phase` | project | `{ phase, state, timestamp, projectId }` |
|
|
215
|
+
| `exit` | project | `{ code, signal, early }` — process exit replay on the WS upgrade |
|
|
216
|
+
| `desktop.project_added` | app | `{ project }` |
|
|
217
|
+
| `desktop.project_removed` | app | `{ projectId }` |
|
|
218
|
+
| `desktop.projects` | app | `{ projects }` |
|
|
219
|
+
|
|
220
|
+
Job lifecycle is reported by the message types `job_started`, `job_completed`, `job_failed`, and `job_canceled`. Feature subsystems add many more (`spending.invalidated`, `plugin.*`, `file.*`, `rail.job_started/completed/stopped`, `explore.contract_refine_failed`, chat/refine/SMASH/proposal streams). See [`api-reference.md`](api-reference.md) for the full outbound-event catalogue.
|
|
221
|
+
|
|
222
|
+
### Client filtering pattern
|
|
223
|
+
|
|
224
|
+
WS handlers use a ref to avoid stale closures:
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
const activeProjectIdRef = useRef(activeProjectId)
|
|
228
|
+
useEffect(() => { activeProjectIdRef.current = activeProjectId }, [activeProjectId])
|
|
229
|
+
|
|
230
|
+
// In a WS message handler:
|
|
231
|
+
if (msg.projectId && msg.projectId !== activeProjectIdRef.current) return
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
App-level messages (no `projectId`) are processed by all handlers.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Process spawning and concurrency
|
|
239
|
+
|
|
240
|
+
`QueueManager` and `ChatManager` spawn the provider CLI (`claude` or `codex`) as subprocesses, always with `cwd` set so the process runs in the correct directory.
|
|
241
|
+
|
|
242
|
+
- **Within a project, jobs run strictly one at a time.** Each `ProjectContext` has exactly one `QueueManager` with a single `_activeJobId`; `_drainQueue()` early-returns while a job is active, so the next rail job queues behind the current one.
|
|
243
|
+
- **Parallelism is across projects only** — each project has its own `QueueManager`, so jobs in different projects run simultaneously. There is no "max concurrent jobs" setting; the only automatic queue-pause is budget-based (daily budget / per-job cost alert).
|
|
244
|
+
- **Cancelling a job** sends `SIGTERM`, waits **5 seconds**, then `SIGKILL`. (The terminal panel's 2-second shutdown grace is a separate subsystem.)
|
|
245
|
+
- A zombie-job watchdog terminates a stuck job after a default of **30 minutes**, overridable via `WM_ZOMBIE_TIMEOUT_MS`.
|
|
246
|
+
- Log lines stream back over WebSocket in real time.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Feature subsystems
|
|
251
|
+
|
|
252
|
+
The app is more than the job pipeline. Each subsystem owns its modules; this is a map, not a duplication of [`CLAUDE.md`](../../CLAUDE.md).
|
|
253
|
+
|
|
254
|
+
| Subsystem | Server modules | Notes |
|
|
255
|
+
|-----------|---------------|-------|
|
|
256
|
+
| **Multi-provider adapters** | `server/providers/{types,claude-adapter,codex-adapter,registry,index}.ts`, `server/provider-selection.ts` | Claude (full native support) and Codex (≥ 0.128.0, estimated cost, synthesized OTEL) behind a `ProviderAdapter` contract. A project can install both; `providers[]` is a JSON column, the first entry is primary. Per-invocation provider is late-bound. See [`adding-a-provider.md`](adding-a-provider.md). |
|
|
257
|
+
| **Spending analytics** | `server/spending.ts`, `server/ai-invocations.ts`, `server/pricing.ts` | `recordInvocation` writes an `ai_invocations` row per AI CLI call across six surfaces (`job`, `quick-spec`, `explore-spec`, `ai-edit`, `smash`, `file-summary`); powers the Analytics page and `spending.invalidated`. |
|
|
258
|
+
| **Agent profiles** | `server/profile-manager.ts`, `server/profiles-router.ts` | Declarative JSON in `.specrails/profiles/*.json`, snapshot-per-job, `SPECRAILS_PROFILE_PATH` env injection. Requires `specrails-core ≥ 4.1.0`. |
|
|
259
|
+
| **Plugins (Integrations)** | `server/plugin-manager.ts`, `server/plugins/` | Bundled-only, MCP-based, additivity invariant, surgical `.mcp.json` merge, `plugin.*` WS events. Serena ships today. |
|
|
260
|
+
| **Terminal panel** | `server/terminal-manager.ts` | `node-pty` sessions over the dedicated `/ws/terminal/:id` socket, OSC shell-integration marks. See [`../terminal.md`](../terminal.md). |
|
|
261
|
+
| **Code explorer** | `server/code-explorer-router.ts`, `server/file-provenance.ts`, `server/file-summary-manager.ts` | Read-only file tree + Monaco viewer + AI summaries; provenance per ticket/job. |
|
|
262
|
+
| **Pipeline telemetry** | `server/telemetry-receiver.ts` + QueueManager OTEL injection | Opt-in OTLP/JSON signals to `POST /otlp/v1/{traces,metrics,logs}`; blobs compacted after 7 days; diagnostic ZIP export. |
|
|
263
|
+
| **Explore acceleration + Contract Refine** | `server/explore-cwd-manager.ts`, `server/contract-refine-runner.ts` | App-managed Explore spawn cwd for fast first-token; optional post-commit Contract Layer enrichment. Kill switches: `SPECRAILS_EXPLORE_CONTRACT_REFINE`, `SPECRAILS_EXPLORE_LEGACY_CWD`. |
|
|
264
|
+
| **Tickets / drafts** | `server/ticket-store.ts` | Spec tickets (incl. `draft` status) backing the Specs board and Save-as-Draft flow. |
|
|
265
|
+
| **Theme system** | `server/desktop-router.ts` (`GET/PATCH /api/theme`) | Five built-in themes (`dracula`, `aurora-light`, `obsidian-dark`, `matrix`, `specrails`), default `specrails`, persisted app-wide with an anti-FOUC inline script. |
|
|
266
|
+
|
|
267
|
+
Most client feature sections are gated by VITE flags, and they share one polarity: `VITE_FEATURE_TERMINAL_PANEL`, `VITE_FEATURE_AGENTS_SECTION`, `VITE_FEATURE_EXPLORE_PREMIUM_UX`, and `VITE_FEATURE_CODE_EXPLORER` are all **opt-out** — default ON, set the flag to `false` to hide that section. See [`configuration.md`](configuration.md) for the full flag and settings reference.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Setup wizard flow
|
|
272
|
+
|
|
273
|
+
When a project is added without specrails-core, the setup wizard runs. The client renders a **3-step** indicator: **Configure → Install → Done**.
|
|
274
|
+
|
|
275
|
+
1. **Configure** — confirm path and pick provider(s) and model presets. (Multi-provider projects get one Configure step per provider.)
|
|
276
|
+
2. **Install** — the app writes `.specrails/install-config.yaml` and runs `npx --yes --prefer-online specrails-core@latest init --yes --from-config <tempPath>`, streaming the log. For multi-provider projects each provider's install runs sequentially.
|
|
277
|
+
3. **Done** — per-provider completion summary.
|
|
278
|
+
|
|
279
|
+
`SetupManager` (server) owns wizard state; `DesktopProvider` (client) tracks which projects are in setup via `setupProjectIds`. The wizard does spawn a real AI CLI for the `/setup` chat, but that spawn is deliberately left uninstrumented (it writes no `ai_invocations` row).
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Desktop app layer
|
|
284
|
+
|
|
285
|
+
The **Tauri v2** desktop app wraps the Vite-built React client as a native macOS/Windows app.
|
|
286
|
+
|
|
287
|
+
- **Server sidecar** — `scripts/build-sidecar.mjs` compiles the Express server to a standalone binary. Tauri bundles it and manages its lifecycle.
|
|
288
|
+
- **Frameless window** — `tauri.conf.json` sets `decorations: false` on all platforms; the custom titlebar (drag region, window controls) is rendered in `TitleBar.tsx`. On macOS the native traffic-light controls are handled there.
|
|
289
|
+
- **GUI-launch PATH** — when launched from Finder/Dock the embedded server inherits a minimal launchd PATH, so `server/path-resolver.ts` resolves a usable PATH before any subprocess spawns (prepending well-known package-manager dirs, or the bundled runtime dirs in desktop mode).
|
|
290
|
+
- **Bundled runtimes** — in desktop mode the Tauri host sets `SPECRAILS_IS_DESKTOP=1` and `SPECRAILS_BUNDLED_RUNTIMES_PATH=<resource_dir>/runtimes` (only when a non-empty `runtimes/` dir is bundled), so the app can run without a system Node/Git. When no bundled runtimes are present it falls back to the system PATH.
|
|
291
|
+
|
|
292
|
+
### Desktop commands
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
npm run dev:desktop # tauri dev (development desktop app)
|
|
296
|
+
npm run build:desktop # build:server + client build + build:sidecar + tauri build
|
|
297
|
+
npm run generate-icons # tauri icon src-tauri/icons/icon.svg
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
> There is no `npm run tauri` script — `npm run tauri dev` / `npm run tauri build` fail with "Missing script: tauri".
|
|
301
|
+
|
|
302
|
+
macOS desktop builds are signed + notarized. Windows builds (x64 and arm64) ship **unsigned** in v1 (SmartScreen "More info → Run anyway"). See [`../platforms/windows.md`](../platforms/windows.md) and [`../platforms/macos.md`](../platforms/macos.md).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Ports
|
|
307
|
+
|
|
308
|
+
| Port | Service |
|
|
309
|
+
|------|---------|
|
|
310
|
+
| `4200` | Express server (API + WebSocket), bound to `127.0.0.1` (overridable via `--port`) |
|
|
311
|
+
| `4201` | Vite dev server (proxies `/api` and `/hooks` to 4200) |
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Security model
|
|
316
|
+
|
|
317
|
+
- **Loopback-only bind** — the server listens on `127.0.0.1` and is not exposed to a network.
|
|
318
|
+
- **Mandatory token auth** — every `/api/*` route and every WebSocket upgrade requires the app token (see [Authentication](#authentication)). The token lives in `~/.specrails/desktop.token` (mode `0600`).
|
|
319
|
+
- **Origin check** — a CORS middleware rejects cross-origin (non-localhost `Origin`) requests with `403`.
|
|
320
|
+
- **Parameterized SQL** — all SQLite operations use parameterized queries; user input is never string-interpolated into SQL.
|
|
321
|
+
- **Path validation** — project paths are validated as existing directories on registration.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## See also
|
|
326
|
+
|
|
327
|
+
- [API reference](api-reference.md) — REST routes and the full WebSocket event catalogue
|
|
328
|
+
- [Configuration](configuration.md) — env vars, feature flags, app/project settings
|
|
329
|
+
- [Agent profiles](profiles.md) — profile schema, resolution order, snapshot-per-job
|
|
330
|
+
- [Adding a provider](adding-a-provider.md) — the `ProviderAdapter` contract
|
|
331
|
+
- [OpenSpec workflow](openspec-workflow.md) — the spec-driven change lifecycle
|
|
332
|
+
- [Operations runbook](operations-runbook.md) — running, upgrading, and recovering the app
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Reference for configuring specrails-desktop: app-wide settings, per-project settings, the authentication token, environment variables, CLI flags, and the `~/.specrails/` data directory.
|
|
4
|
+
|
|
5
|
+
Everything here is verified against the shipped code (v1.63.1). The app server binds to `127.0.0.1` only and rejects any non-localhost origin, so all of this is local-first by design.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
The app is protected by a **mandatory** API token — there is no "off" switch and no UI to set it.
|
|
12
|
+
|
|
13
|
+
- On first run the server generates a token (two concatenated random UUIDs) and writes it to `~/.specrails/desktop.token` with mode `0600`. The same file is reused on every subsequent start.
|
|
14
|
+
- Every `/api/*` route requires the token via an `Authorization: Bearer <token>` or `X-Desktop-Token: <token>` header. The only exceptions are `GET /api/health` and `GET /api/token`.
|
|
15
|
+
- WebSocket upgrades carry the token as the `desktop-token.<token>` subprotocol.
|
|
16
|
+
- The browser client fetches the token same-origin from `GET /api/token`, so you never type it in.
|
|
17
|
+
|
|
18
|
+
Two more layers keep the app local-only:
|
|
19
|
+
|
|
20
|
+
- **Loopback bind** — the server listens on `127.0.0.1` exclusively (`server.listen(port, '127.0.0.1')`).
|
|
21
|
+
- **CORS allow-list** — only `localhost`, `127.0.0.1`, `tauri.localhost`, and `tauri://localhost` origins are accepted; anything else gets a `403`.
|
|
22
|
+
|
|
23
|
+
To rotate the token, stop the app, delete `~/.specrails/desktop.token`, and start again — a fresh token is generated.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## App settings
|
|
28
|
+
|
|
29
|
+
App settings apply across all projects. Open them from the **left sidebar → Settings**, or via the Command Palette (`Cmd/Ctrl+K`) → **Desktop Settings**. They are persisted in `~/.specrails/desktop.sqlite` under the `desktop_settings` key/value table.
|
|
30
|
+
|
|
31
|
+
The Global Settings page is organised into these sections:
|
|
32
|
+
|
|
33
|
+
| Section | What it controls | Stored key / default |
|
|
34
|
+
|---------|------------------|----------------------|
|
|
35
|
+
| **Appearance** | App-wide UI theme. Five built-ins: `specrails` (default), `dracula`, `aurora-light`, `obsidian-dark`, `matrix`. | `ui_theme` = `specrails` |
|
|
36
|
+
| **specrails-tech** | Base URL for the external specrails-tech agents service. | `specrails_tech_url` = `http://localhost:3000` (the `SPECRAILS_TECH_URL` env var is only a fallback when this setting is unset — the stored setting wins) |
|
|
37
|
+
| **Budget & Alerts** | App-wide daily spend cap (queues auto-pause when exceeded) and a per-job cost alert threshold. | `desktop_daily_budget_usd`, `cost_alert_threshold_usd` (both unset by default = no cap / no alert) |
|
|
38
|
+
| **OS Notifications** | Desktop notification preferences for long-running jobs and budget events. | — |
|
|
39
|
+
| **Outbound Webhooks** | HTTP webhooks fired on `job.completed`, `job.failed`, `job.canceled`, `daily_budget_exceeded`, and `desktop_daily_budget_exceeded`. | webhooks table (defaults to `["job.completed","job.failed"]` per hook) |
|
|
40
|
+
| **Code section** | Plain-language file-summary language (`en` / `es`) and the monthly summary budget cap. | `summary_language` = `en`, `summary_monthly_budget_usd` = `5.00` |
|
|
41
|
+
| **Terminal Panel** | App-wide defaults for the integrated terminal (font, render mode, copy-on-select, shell integration, image rendering, long-command threshold). | `terminal.*` keys |
|
|
42
|
+
|
|
43
|
+
> There is **no** "Claude model", "Max concurrent jobs", "Job timeout", or "Authentication token" app setting. Within a project, jobs run one at a time (see [Architecture](architecture.md)); the only automatic queue pause is budget-based. The default model is the provider adapter's default (the `sonnet` alias for Claude), resolved at spawn time — it is not a stored setting.
|
|
44
|
+
|
|
45
|
+
**Port is not a live setting.** `desktop_settings` does store a `port` value, but it is display-only. The port the server actually binds is taken from the `--port` argv (default `4200`); changing the stored value does not rebind a running server. Set the port with `--port <n>` on `specrails-desktop start`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Project settings
|
|
50
|
+
|
|
51
|
+
Project settings apply to a single project. Open them from the project's **Settings** entry in the right sidebar (route: `/settings`). The page is titled **Project Settings** and has these sections:
|
|
52
|
+
|
|
53
|
+
| Section | What it controls |
|
|
54
|
+
|---------|------------------|
|
|
55
|
+
| **Pipeline Telemetry** | Opt-in toggle that injects OpenTelemetry env vars into pipeline job spawns so they emit OTLP signals back to the app. Off by default. |
|
|
56
|
+
| **Rail Pre-prompt** | Text prepended to every rail launch for this project. |
|
|
57
|
+
| **Ultracode pre-prompt** | Text prepended to Ultracode-mode launches (the Claude-only autonomous rail mode). |
|
|
58
|
+
| **Budget** | Per-project daily spend cap (with queue auto-pause) and a per-job cost alert threshold. |
|
|
59
|
+
| **Terminal Settings** | Per-project overrides for the terminal panel defaults (project override → app default → built-in). |
|
|
60
|
+
|
|
61
|
+
> The project's **provider(s)** (Claude, Codex, or both) are chosen when you add the project and are **immutable after creation** — there is no provider switch in Project Settings. There is also **no** Name edit, Path row, or model-override field on this page.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## CLI
|
|
66
|
+
|
|
67
|
+
The `specrails-desktop` CLI is documented in full in [../cli.md](../cli.md). Quick reference:
|
|
68
|
+
|
|
69
|
+
### Global flags
|
|
70
|
+
|
|
71
|
+
These can appear in any position and are stripped before the command runs.
|
|
72
|
+
|
|
73
|
+
| Flag | Description | Default |
|
|
74
|
+
|------|-------------|---------|
|
|
75
|
+
| `--port <n>` | Connect to (or start) the app on port `<n>` | `4200` |
|
|
76
|
+
| `--project <name\|path>` | Target a specific registered project (by name or path) | auto-detect from `cwd` |
|
|
77
|
+
| `--version`, `-v` | Print the CLI version and exit | — |
|
|
78
|
+
| `--help`, `-h` | Print usage and exit | — |
|
|
79
|
+
| `--status` | Print server status and exit | — |
|
|
80
|
+
|
|
81
|
+
> Project auto-detection is an **exact canonical-path match** (`realpathSync(cwd)` compared against registered project paths). It does **not** walk up parent directories — running from a subdirectory of a registered project will not match. Use `--project` to target a project from anywhere.
|
|
82
|
+
|
|
83
|
+
### Server management
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
specrails-desktop start # Start the app server (daemonized)
|
|
87
|
+
specrails-desktop stop # Stop the app server
|
|
88
|
+
specrails-desktop list # List all registered projects
|
|
89
|
+
specrails-desktop add <path> # Register a project by absolute path
|
|
90
|
+
specrails-desktop remove <project-id> # Unregister a project by ID
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Running work
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
specrails-desktop implement "#42" # Queue /specrails:implement for spec #42
|
|
97
|
+
specrails-desktop batch-implement "#40" "#41" "#43" # Queue one batch job over several specs
|
|
98
|
+
specrails-desktop "any raw prompt" # Pass a raw prompt straight to the AI CLI
|
|
99
|
+
specrails-desktop /specrails:health-check # Pass any slash command directly
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> **Always quote issue refs.** An unquoted `#` starts a shell comment, so `batch-implement #40 #41` silently drops the refs. Quote each one: `"#40" "#41"`.
|
|
103
|
+
|
|
104
|
+
**Known verbs** (automatically prefixed with `/specrails:`): `implement`, `batch-implement`, `why`, `get-backlog-specs`, `auto-propose-backlog-specs`, `propose-spec`, `refactor-recommender`, `health-check`, `compat-check`, `enrich`. Any other first argument is passed as a raw prompt.
|
|
105
|
+
|
|
106
|
+
### Port override example
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
specrails-desktop --port 5000 start
|
|
110
|
+
specrails-desktop --port 5000 implement "#42"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Environment variables
|
|
116
|
+
|
|
117
|
+
A few env vars are read directly by the app. The two most useful operational ones:
|
|
118
|
+
|
|
119
|
+
| Variable | Description |
|
|
120
|
+
|----------|-------------|
|
|
121
|
+
| `SPECRAILS_TECH_URL` | Fallback specrails-tech base URL. Resolution order is the `specrails_tech_url` app setting **first**, then this env var, then `http://localhost:3000` — so a stored app setting takes precedence over this var. |
|
|
122
|
+
| `WM_ZOMBIE_TIMEOUT_MS` | Zombie-job detection timeout in milliseconds (default `1800000` = 30 min). This is a stuck-job watchdog, **not** a hard "kill after N minutes" cap. |
|
|
123
|
+
|
|
124
|
+
`ANTHROPIC_API_KEY` is **not** read by the app. The Claude CLI authenticates on its own — via a Claude subscription login or its own API-key configuration — so you do not set it for the app.
|
|
125
|
+
|
|
126
|
+
For the full catalogue of feature flags and kill switches (`SPECRAILS_*` server gates, `VITE_FEATURE_*` client flags, `SPECRAILS_CODEX_BETA`, `SPECRAILS_EXPLORE_*`), see [../customizing.md](../customizing.md#environment-variables).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## `~/.specrails/` directory structure
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
~/.specrails/
|
|
134
|
+
desktop.sqlite # App-level SQLite: project registry + desktop_settings
|
|
135
|
+
desktop.token # Auto-generated API token (mode 0600)
|
|
136
|
+
manager.pid # PID of the running specrails-desktop server process
|
|
137
|
+
desktop.log # Server stdout/stderr (appended on each start)
|
|
138
|
+
projects/
|
|
139
|
+
<project-slug>/
|
|
140
|
+
jobs.sqlite # Per-project job history, invocations, telemetry pointers
|
|
141
|
+
jobs/<jobId>/ # Per-job snapshots (profile.json, plugins.json) — chmod 400
|
|
142
|
+
telemetry/ # OTEL blobs (<jobId>.ndjson.gz) when telemetry is on
|
|
143
|
+
explore-cwd/ # App-managed cwd for Explore Spec turns
|
|
144
|
+
terminals/ # Per-session shell-integration shim dirs
|
|
145
|
+
codex-home/ # Per-project CODEX_HOME (Codex projects only)
|
|
146
|
+
browser-profile/ # Persistent browser-capture profile
|
|
147
|
+
attachments/ # Spec attachments, keyed by ticket
|
|
148
|
+
user-mcp.json # Materialised user-approved MCP config (chmod 600)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Slug generation.** The slug is derived from the project directory name: lowercased, every run of non-alphanumeric characters collapsed to a single hyphen, and leading/trailing hyphens stripped. Example: `My App v2!` → `my-app-v2`.
|
|
152
|
+
|
|
153
|
+
**Backup.** To back up all app data, copy `~/.specrails/`. Your project source code lives in your repos, not here.
|
|
154
|
+
|
|
155
|
+
**Reset.** To clear project registrations and job history:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
specrails-desktop stop
|
|
159
|
+
rm -rf ~/.specrails/desktop.sqlite ~/.specrails/projects/
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
> This leaves `desktop.token`, `manager.pid`, and `desktop.log` in place. For a full wipe (including the API token), `rm -rf ~/.specrails`. Either way, your project source and specrails-core installations are untouched.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Further reading
|
|
167
|
+
|
|
168
|
+
- [Getting started](../getting-started.md) — user-facing install guide
|
|
169
|
+
- [Architecture](architecture.md) — server modules, data flow, WebSocket protocol
|
|
170
|
+
- [CLI reference](../cli.md) — every command and flag in detail
|
|
171
|
+
- [Customising the app](../customizing.md) — feature flags, env vars, keybindings
|
|
172
|
+
- [Adding a provider](adding-a-provider.md) — wiring a third AI CLI adapter
|