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,443 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ProjectRegistry = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const db_1 = require("./db");
|
|
11
|
+
const queue_manager_1 = require("./queue-manager");
|
|
12
|
+
const chat_manager_1 = require("./chat-manager");
|
|
13
|
+
const setup_manager_1 = require("./setup-manager");
|
|
14
|
+
const proposal_manager_1 = require("./proposal-manager");
|
|
15
|
+
const agent_refine_manager_1 = require("./agent-refine-manager");
|
|
16
|
+
const file_summary_manager_1 = require("./file-summary-manager");
|
|
17
|
+
const file_summary_generator_1 = require("./file-summary-generator");
|
|
18
|
+
const providers_1 = require("./providers");
|
|
19
|
+
const agent_refine_db_1 = require("./agent-refine-db");
|
|
20
|
+
const spec_launcher_manager_1 = require("./spec-launcher-manager");
|
|
21
|
+
const webhook_manager_1 = require("./webhook-manager");
|
|
22
|
+
const ticket_watcher_1 = require("./ticket-watcher");
|
|
23
|
+
const terminal_manager_1 = require("./terminal-manager");
|
|
24
|
+
const browser_capture_manager_1 = require("./browser-capture-manager");
|
|
25
|
+
const explore_cwd_manager_1 = require("./explore-cwd-manager");
|
|
26
|
+
const ticket_store_1 = require("./ticket-store");
|
|
27
|
+
const rails_store_1 = require("./rails-store");
|
|
28
|
+
const desktop_db_1 = require("./desktop-db");
|
|
29
|
+
const config_1 = require("./config");
|
|
30
|
+
// ─── ProjectRegistry ──────────────────────────────────────────────────────────
|
|
31
|
+
class ProjectRegistry {
|
|
32
|
+
_desktopDb;
|
|
33
|
+
_contexts;
|
|
34
|
+
_broadcast;
|
|
35
|
+
_webhookManager;
|
|
36
|
+
_desktopPort;
|
|
37
|
+
// M9: projects whose per-project DB failed to load at startup (corrupt, locked,
|
|
38
|
+
// or migration-stuck). They stay registered but have no live context.
|
|
39
|
+
_failedProjects;
|
|
40
|
+
constructor(broadcast, desktopDbPath, desktopPort) {
|
|
41
|
+
this._broadcast = broadcast;
|
|
42
|
+
this._desktopDb = (0, desktop_db_1.initDesktopDb)(desktopDbPath ?? (0, desktop_db_1.getDesktopDbPath)());
|
|
43
|
+
this._contexts = new Map();
|
|
44
|
+
this._webhookManager = new webhook_manager_1.WebhookManager(this._desktopDb);
|
|
45
|
+
this._desktopPort = desktopPort ?? 4200;
|
|
46
|
+
this._failedProjects = new Map();
|
|
47
|
+
}
|
|
48
|
+
get desktopDb() {
|
|
49
|
+
return this._desktopDb;
|
|
50
|
+
}
|
|
51
|
+
loadAll() {
|
|
52
|
+
const projects = (0, desktop_db_1.listProjects)(this._desktopDb);
|
|
53
|
+
for (const project of projects) {
|
|
54
|
+
try {
|
|
55
|
+
this._loadProjectContext(project);
|
|
56
|
+
this._failedProjects.delete(project.id);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
// M9: a single corrupt / locked / migration-stuck per-project jobs.sqlite
|
|
60
|
+
// must NOT crash the whole app at startup (previously it did, killing
|
|
61
|
+
// every other project + the UI in a restart loop). Log it, record it as
|
|
62
|
+
// failed-to-load, and keep loading the rest.
|
|
63
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
64
|
+
console.error(`[project-registry] failed to load project ${project.id} (${project.slug}): ${msg}`);
|
|
65
|
+
this._failedProjects.set(project.id, { project, error: msg });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Projects whose per-project DB failed to load at startup (M9). */
|
|
70
|
+
listFailedProjects() {
|
|
71
|
+
return Array.from(this._failedProjects.values());
|
|
72
|
+
}
|
|
73
|
+
addProject(opts) {
|
|
74
|
+
const row = (0, desktop_db_1.addProject)(this._desktopDb, opts);
|
|
75
|
+
return this._loadProjectContext(row);
|
|
76
|
+
}
|
|
77
|
+
removeProject(id) {
|
|
78
|
+
const ctx = this._contexts.get(id);
|
|
79
|
+
if (ctx) {
|
|
80
|
+
// Tear down spawners BEFORE closing the DB. QueueManager.shutdown() drops
|
|
81
|
+
// its DB handle so a late child 'close' can't run prepared statements on
|
|
82
|
+
// the closed connection (which would crash the app) and terminates any
|
|
83
|
+
// orphaned rail child + dangling zombie timer. ChatManager.shutdown()
|
|
84
|
+
// kills in-flight chat/Explore children and clears their idle timers.
|
|
85
|
+
// SetupManager.abort() stops the 3s install poll and kills install/enrich
|
|
86
|
+
// children. All are idempotent no-ops when nothing is running.
|
|
87
|
+
try {
|
|
88
|
+
ctx.queueManager.shutdown();
|
|
89
|
+
}
|
|
90
|
+
catch { /* ignore */ }
|
|
91
|
+
try {
|
|
92
|
+
ctx.chatManager.shutdown();
|
|
93
|
+
}
|
|
94
|
+
catch { /* ignore */ }
|
|
95
|
+
try {
|
|
96
|
+
ctx.setupManager.abort(id);
|
|
97
|
+
}
|
|
98
|
+
catch { /* ignore */ }
|
|
99
|
+
// M12: these three also spawn children that outlive removeProject. Proposal
|
|
100
|
+
// and AgentRefine write to the per-project DB in their close handlers — if
|
|
101
|
+
// not disposed before db.close() they throw on the closed connection and
|
|
102
|
+
// (no uncaughtException handler) crash the entire app. SpecLauncher has no
|
|
103
|
+
// DB but its --dangerously-skip-permissions child keeps burning spend.
|
|
104
|
+
try {
|
|
105
|
+
ctx.proposalManager.shutdown();
|
|
106
|
+
}
|
|
107
|
+
catch { /* ignore */ }
|
|
108
|
+
try {
|
|
109
|
+
ctx.agentRefineManager.shutdown();
|
|
110
|
+
}
|
|
111
|
+
catch { /* ignore */ }
|
|
112
|
+
try {
|
|
113
|
+
ctx.specLauncherManager.shutdown();
|
|
114
|
+
}
|
|
115
|
+
catch { /* ignore */ }
|
|
116
|
+
// Tear down the embedded browser (closes pages + persistent context).
|
|
117
|
+
void ctx.browserCaptureManager.shutdown().catch(() => { });
|
|
118
|
+
// Kill any terminal sessions belonging to this project
|
|
119
|
+
try {
|
|
120
|
+
(0, terminal_manager_1.getTerminalManager)().killAllForProject(id);
|
|
121
|
+
}
|
|
122
|
+
catch { /* ignore */ }
|
|
123
|
+
// Close the ticket file watcher
|
|
124
|
+
ctx.ticketWatcher.close().catch(() => { });
|
|
125
|
+
// Tear down the code-explorer summary manager: aborts any in-flight
|
|
126
|
+
// provider child, rejects queued work, and detaches the watcher — BEFORE
|
|
127
|
+
// db.close() so a completing generation can't write to the closed handle.
|
|
128
|
+
try {
|
|
129
|
+
ctx.fileSummaryManager.dispose();
|
|
130
|
+
}
|
|
131
|
+
catch { /* ignore */ }
|
|
132
|
+
// Drop the app-managed Explore Spec cwd (CLAUDE.md + symlink to project)
|
|
133
|
+
try {
|
|
134
|
+
(0, explore_cwd_manager_1.removeExploreCwd)(ctx.project.slug);
|
|
135
|
+
}
|
|
136
|
+
catch { /* ignore — non-fatal */ }
|
|
137
|
+
// Close the DB connection BEFORE removing the project's data dir below.
|
|
138
|
+
try {
|
|
139
|
+
ctx.db.close();
|
|
140
|
+
}
|
|
141
|
+
catch { /* ignore */ }
|
|
142
|
+
// B54: remove the ENTIRE app-managed data dir for this project, not just
|
|
143
|
+
// the telemetry subdir. It also holds user-mcp.json (a copy of the user's
|
|
144
|
+
// MCP config that can contain API keys), profile snapshots, codex-home, and
|
|
145
|
+
// terminal shim dirs — all secret-bearing residue that previously survived
|
|
146
|
+
// project removal. Guard on a non-empty slug so we never rm the projects/
|
|
147
|
+
// root itself.
|
|
148
|
+
try {
|
|
149
|
+
const slug = ctx.project.slug;
|
|
150
|
+
if (slug && slug.trim() && !slug.includes('/') && !slug.includes('..')) {
|
|
151
|
+
const projectDir = path_1.default.join(os_1.default.homedir(), '.specrails', 'projects', slug);
|
|
152
|
+
if (fs_1.default.existsSync(projectDir)) {
|
|
153
|
+
fs_1.default.rmSync(projectDir, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch { /* ignore — non-fatal */ }
|
|
158
|
+
this._contexts.delete(id);
|
|
159
|
+
}
|
|
160
|
+
(0, desktop_db_1.removeProject)(this._desktopDb, id);
|
|
161
|
+
}
|
|
162
|
+
getContext(id) {
|
|
163
|
+
return this._contexts.get(id);
|
|
164
|
+
}
|
|
165
|
+
getContextByPath(projectPath) {
|
|
166
|
+
const row = (0, desktop_db_1.getProjectByPath)(this._desktopDb, projectPath);
|
|
167
|
+
if (!row)
|
|
168
|
+
return undefined;
|
|
169
|
+
return this._contexts.get(row.id);
|
|
170
|
+
}
|
|
171
|
+
listContexts() {
|
|
172
|
+
return Array.from(this._contexts.values());
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Graceful process-level teardown: terminate every project's active rail and
|
|
176
|
+
* chat children so SIGTERM/SIGINT (or desktop parent-death) does not leave
|
|
177
|
+
* orphaned claude/codex processes reparented to init. Best-effort per project
|
|
178
|
+
* — one failure never blocks the rest. Does NOT close DBs (the process is
|
|
179
|
+
* exiting anyway).
|
|
180
|
+
*/
|
|
181
|
+
shutdown() {
|
|
182
|
+
for (const ctx of this._contexts.values()) {
|
|
183
|
+
try {
|
|
184
|
+
ctx.queueManager.shutdown();
|
|
185
|
+
}
|
|
186
|
+
catch { /* ignore */ }
|
|
187
|
+
try {
|
|
188
|
+
ctx.chatManager.shutdown();
|
|
189
|
+
}
|
|
190
|
+
catch { /* ignore */ }
|
|
191
|
+
try {
|
|
192
|
+
ctx.proposalManager.shutdown();
|
|
193
|
+
}
|
|
194
|
+
catch { /* ignore */ }
|
|
195
|
+
try {
|
|
196
|
+
ctx.agentRefineManager.shutdown();
|
|
197
|
+
}
|
|
198
|
+
catch { /* ignore */ }
|
|
199
|
+
try {
|
|
200
|
+
ctx.specLauncherManager.shutdown();
|
|
201
|
+
}
|
|
202
|
+
catch { /* ignore */ }
|
|
203
|
+
void ctx.browserCaptureManager.shutdown().catch(() => { });
|
|
204
|
+
// Release chokidar watchers + abort in-flight generations so a restart
|
|
205
|
+
// does not leak handles/children — mirror removeProject()'s per-project teardown.
|
|
206
|
+
try {
|
|
207
|
+
ctx.fileSummaryManager.dispose();
|
|
208
|
+
}
|
|
209
|
+
catch { /* ignore */ }
|
|
210
|
+
ctx.ticketWatcher.close().catch(() => { });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
touchProject(id) {
|
|
214
|
+
(0, desktop_db_1.touchProject)(this._desktopDb, id);
|
|
215
|
+
}
|
|
216
|
+
getProjectRow(id) {
|
|
217
|
+
return (0, desktop_db_1.getProject)(this._desktopDb, id);
|
|
218
|
+
}
|
|
219
|
+
_loadProjectContext(project) {
|
|
220
|
+
// Avoid double-loading
|
|
221
|
+
const existing = this._contexts.get(project.id);
|
|
222
|
+
if (existing)
|
|
223
|
+
return existing;
|
|
224
|
+
const db = (0, db_1.initDb)(project.db_path);
|
|
225
|
+
// Bind broadcast with projectId so all WS messages carry context.
|
|
226
|
+
// Also wire agent status: when a queued job reaches a terminal state,
|
|
227
|
+
// clear current_job_id on any agent that was assigned to it.
|
|
228
|
+
const TERMINAL_JOB_STATUSES = new Set(['completed', 'failed', 'canceled']);
|
|
229
|
+
const boundBroadcast = (msg) => {
|
|
230
|
+
const enriched = { ...msg, projectId: project.id };
|
|
231
|
+
this._broadcast(enriched);
|
|
232
|
+
if (msg.type === 'queue') {
|
|
233
|
+
for (const job of msg.jobs) {
|
|
234
|
+
if (TERMINAL_JOB_STATUSES.has(job.status)) {
|
|
235
|
+
(0, desktop_db_1.clearAgentJob)(this._desktopDb, job.id);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
// Per-project zombie timeout (stored in queue_state)
|
|
241
|
+
let projectZombieTimeout;
|
|
242
|
+
try {
|
|
243
|
+
const row = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.zombie_timeout_ms'`).get();
|
|
244
|
+
if (row) {
|
|
245
|
+
const parsed = parseInt(row.value, 10);
|
|
246
|
+
if (!isNaN(parsed) && parsed > 0)
|
|
247
|
+
projectZombieTimeout = parsed;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch { /* queue_state table may not exist yet */ }
|
|
251
|
+
const webhookManager = this._webhookManager;
|
|
252
|
+
const railJobs = new Map();
|
|
253
|
+
const queueManager = new queue_manager_1.QueueManager(boundBroadcast, db, undefined, project.path, {
|
|
254
|
+
zombieTimeoutMs: projectZombieTimeout,
|
|
255
|
+
provider: project.provider ?? 'claude',
|
|
256
|
+
projectId: project.id,
|
|
257
|
+
projectSlug: project.slug,
|
|
258
|
+
desktopPort: this._desktopPort,
|
|
259
|
+
getCostAlertThreshold: () => {
|
|
260
|
+
const val = (0, desktop_db_1.getDesktopSetting)(this._desktopDb, 'cost_alert_threshold_usd');
|
|
261
|
+
return val != null ? parseFloat(val) : null;
|
|
262
|
+
},
|
|
263
|
+
getDesktopDailyBudget: () => {
|
|
264
|
+
const val = (0, desktop_db_1.getDesktopSetting)(this._desktopDb, 'desktop_daily_budget_usd');
|
|
265
|
+
const budget = val != null ? parseFloat(val) : null;
|
|
266
|
+
let totalSpend = 0;
|
|
267
|
+
for (const c of this.listContexts()) {
|
|
268
|
+
const row = c.db.prepare(`SELECT COALESCE(SUM(total_cost_usd), 0) as total FROM jobs WHERE status = 'completed' AND total_cost_usd IS NOT NULL AND started_at >= date('now')`).get();
|
|
269
|
+
totalSpend += row.total;
|
|
270
|
+
}
|
|
271
|
+
return { budget, totalSpend };
|
|
272
|
+
},
|
|
273
|
+
onJobFinished: (jobId, status, costUsd) => {
|
|
274
|
+
const jobRow = db.prepare('SELECT command, duration_ms FROM jobs WHERE id = ?').get(jobId);
|
|
275
|
+
const event = status === 'completed' ? 'job.completed' : status === 'canceled' ? 'job.canceled' : 'job.failed';
|
|
276
|
+
webhookManager.deliver(project.id, event, {
|
|
277
|
+
jobId,
|
|
278
|
+
command: jobRow?.command ?? '',
|
|
279
|
+
status,
|
|
280
|
+
costUsd: costUsd ?? null,
|
|
281
|
+
durationMs: jobRow?.duration_ms ?? null,
|
|
282
|
+
});
|
|
283
|
+
// Broadcast rail.job_completed if this job was launched by a rail
|
|
284
|
+
const railMeta = railJobs.get(jobId);
|
|
285
|
+
if (railMeta) {
|
|
286
|
+
railJobs.delete(jobId);
|
|
287
|
+
}
|
|
288
|
+
// Determine ticket IDs: from rail metadata, or parse from command as fallback
|
|
289
|
+
// (railJobs Map is in-memory and lost on server restart)
|
|
290
|
+
let completedTicketIds = railMeta?.ticketIds ?? [];
|
|
291
|
+
if (completedTicketIds.length === 0 && jobRow?.command) {
|
|
292
|
+
const matches = jobRow.command.match(/#(\d+)/g);
|
|
293
|
+
if (matches)
|
|
294
|
+
completedTicketIds = matches.map((m) => parseInt(m.slice(1), 10));
|
|
295
|
+
}
|
|
296
|
+
// Apply the job outcome to its tickets. Success promotes todo/in_progress
|
|
297
|
+
// → done (→ Specs Done); failure/cancel/zombie reverts in_progress → todo
|
|
298
|
+
// (→ Specs) or flags an already-done spec for review. zombie_terminated is
|
|
299
|
+
// treated as a failure here (and is included in the _onJobExit callback
|
|
300
|
+
// guard) so a timed-out rail releases its specs instead of stranding them.
|
|
301
|
+
if (completedTicketIds.length > 0 &&
|
|
302
|
+
(status === 'completed' || status === 'failed' || status === 'canceled' || status === 'zombie_terminated')) {
|
|
303
|
+
try {
|
|
304
|
+
const ticketFile = (0, ticket_store_1.resolveTicketStoragePath)(project.path);
|
|
305
|
+
const now = new Date().toISOString();
|
|
306
|
+
let changedIds = [];
|
|
307
|
+
const store = (0, ticket_store_1.mutateStore)(ticketFile, (s) => {
|
|
308
|
+
changedIds = (0, ticket_store_1.applyJobOutcomeToTickets)(s, completedTicketIds, status, now);
|
|
309
|
+
});
|
|
310
|
+
for (const tid of changedIds) {
|
|
311
|
+
const ticket = store.tickets[String(tid)];
|
|
312
|
+
if (!ticket)
|
|
313
|
+
continue;
|
|
314
|
+
boundBroadcast({
|
|
315
|
+
type: 'ticket_updated',
|
|
316
|
+
ticket: ticket,
|
|
317
|
+
projectId: project.id,
|
|
318
|
+
timestamp: ticket.updated_at,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
console.error('[project-registry] failed to apply job outcome to tickets:', err);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Release the job's tickets from any rail that still holds them. The
|
|
327
|
+
// server `rails` table is the source of truth for mobile clients (the
|
|
328
|
+
// desktop strips its localStorage copy on rail.job_completed) — without
|
|
329
|
+
// this, a finished spec stays stranded on the rail forever. Runs on
|
|
330
|
+
// every terminal outcome, mirroring the desktop: success → spec is
|
|
331
|
+
// done; failure/cancel/zombie → spec returns to the board. Scans ALL
|
|
332
|
+
// rails (not just railMeta.railIndex) so it also heals after a server
|
|
333
|
+
// restart, when the in-memory railJobs map is lost.
|
|
334
|
+
if (completedTicketIds.length > 0 &&
|
|
335
|
+
(status === 'completed' || status === 'failed' || status === 'canceled' || status === 'zombie_terminated')) {
|
|
336
|
+
try {
|
|
337
|
+
for (const rail of (0, rails_store_1.getRails)(db)) {
|
|
338
|
+
const remaining = rail.ticketIds.filter((id) => !completedTicketIds.includes(id));
|
|
339
|
+
if (remaining.length === rail.ticketIds.length)
|
|
340
|
+
continue;
|
|
341
|
+
(0, rails_store_1.setRailTickets)(db, rail.railIndex, remaining, rail.mode, rail.profileName, rail.aiEngine);
|
|
342
|
+
boundBroadcast({
|
|
343
|
+
type: 'rail.updated',
|
|
344
|
+
projectId: project.id,
|
|
345
|
+
railIndex: rail.railIndex,
|
|
346
|
+
changed: 'tickets',
|
|
347
|
+
ticketIds: remaining,
|
|
348
|
+
name: rail.name ?? null,
|
|
349
|
+
mode: rail.mode,
|
|
350
|
+
profileName: rail.profileName ?? null,
|
|
351
|
+
aiEngine: rail.aiEngine ?? null,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
catch (err) {
|
|
356
|
+
console.error('[project-registry] failed to release rail tickets after job exit:', err);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// Broadcast rail.job_completed if we know the rail index
|
|
360
|
+
if (railMeta) {
|
|
361
|
+
boundBroadcast({
|
|
362
|
+
type: 'rail.job_completed',
|
|
363
|
+
projectId: project.id,
|
|
364
|
+
railIndex: railMeta.railIndex,
|
|
365
|
+
jobId,
|
|
366
|
+
status,
|
|
367
|
+
ticketIds: completedTicketIds,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
const chatManager = new chat_manager_1.ChatManager(boundBroadcast, db, project.path, project.name, project.provider ?? 'claude', project.id, project.slug);
|
|
373
|
+
const setupManager = new setup_manager_1.SetupManager(boundBroadcast, (pid, sid) => (0, desktop_db_1.setProjectSetupSession)(this._desktopDb, pid, sid), (pid) => (0, desktop_db_1.clearProjectSetupSession)(this._desktopDb, pid));
|
|
374
|
+
const proposalManager = new proposal_manager_1.ProposalManager(boundBroadcast, db, project.path);
|
|
375
|
+
const agentRefineManager = new agent_refine_manager_1.AgentRefineManager(boundBroadcast, db, project.path, project.id, project.provider ?? 'claude');
|
|
376
|
+
// Retention prune: drop stale/abandoned refine sessions on project load.
|
|
377
|
+
try {
|
|
378
|
+
(0, agent_refine_db_1.pruneStaleRefineSessions)(db);
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
console.error('[project-registry] prune refine sessions failed:', err);
|
|
382
|
+
}
|
|
383
|
+
const specLauncherManager = new spec_launcher_manager_1.SpecLauncherManager(boundBroadcast, project.path);
|
|
384
|
+
// FileSummaryManager — code-explorer. The class is constructed for every
|
|
385
|
+
// project regardless of the feature flag; the router 404s when the flag
|
|
386
|
+
// is off, so no spawn can occur. Budget reader queries `ai_invocations`
|
|
387
|
+
// for the current calendar month.
|
|
388
|
+
const fileSummaryAdapter = (0, providers_1.getAdapter)(project.provider ?? 'claude');
|
|
389
|
+
const fileSummaryGenerate = (0, file_summary_generator_1.createFileSummaryGenerator)({ adapter: fileSummaryAdapter, cwd: project.path });
|
|
390
|
+
const fileSummaryManager = new file_summary_manager_1.FileSummaryManager({
|
|
391
|
+
db,
|
|
392
|
+
broadcast: boundBroadcast,
|
|
393
|
+
generate: fileSummaryGenerate,
|
|
394
|
+
monthToDateSpend: (projectId) => {
|
|
395
|
+
const row = db.prepare(`SELECT COALESCE(SUM(total_cost_usd), 0) AS total FROM ai_invocations
|
|
396
|
+
WHERE project_id = ? AND surface = 'file-summary'
|
|
397
|
+
AND started_at >= strftime('%Y-%m-01', 'now')`).get(projectId);
|
|
398
|
+
return row?.total ?? 0;
|
|
399
|
+
},
|
|
400
|
+
monthlyBudgetUsd: () => {
|
|
401
|
+
const raw = (0, desktop_db_1.getDesktopSetting)(this._desktopDb, 'summary_monthly_budget_usd');
|
|
402
|
+
const n = parseFloat(raw ?? '5.00');
|
|
403
|
+
return isNaN(n) ? 5.0 : n;
|
|
404
|
+
},
|
|
405
|
+
language: () => {
|
|
406
|
+
const raw = (0, desktop_db_1.getDesktopSetting)(this._desktopDb, 'summary_language');
|
|
407
|
+
return raw === 'es' ? 'es' : 'en';
|
|
408
|
+
},
|
|
409
|
+
providerId: () => fileSummaryAdapter.id,
|
|
410
|
+
});
|
|
411
|
+
// NOTE: the chokidar watcher is NOT attached here. It is only needed to mark
|
|
412
|
+
// already-generated summaries stale, which is irrelevant until the user opens
|
|
413
|
+
// the Code section. Attaching at startup for every project — even ones that
|
|
414
|
+
// never use Code Explorer (the client flag is OFF by default) — added a
|
|
415
|
+
// persistent recursive watcher per project, the source of the fd leak that
|
|
416
|
+
// broke terminals. The watcher is now attached lazily on the first
|
|
417
|
+
// code-explorer request (see code-explorer-router.ts).
|
|
418
|
+
// Load commands for this project
|
|
419
|
+
try {
|
|
420
|
+
const config = (0, config_1.getConfig)(project.path, db, project.name);
|
|
421
|
+
queueManager.setCommands(config.commands);
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
// Non-fatal: project may not have commands yet
|
|
425
|
+
}
|
|
426
|
+
const ticketWatcher = new ticket_watcher_1.TicketWatcher(project.path, project.id, boundBroadcast);
|
|
427
|
+
ticketWatcher.start();
|
|
428
|
+
// BrowserCaptureManager — "Add Spec from browser". Constructed for every
|
|
429
|
+
// project regardless of the feature flag; the routes + WS endpoint 404 when
|
|
430
|
+
// the flag is off, and the persistent Chromium context is launched lazily on
|
|
431
|
+
// first session create, so a project that never uses it pays nothing.
|
|
432
|
+
const browserCaptureManager = new browser_capture_manager_1.BrowserCaptureManager({
|
|
433
|
+
projectId: project.id,
|
|
434
|
+
projectSlug: project.slug,
|
|
435
|
+
db,
|
|
436
|
+
broadcast: boundBroadcast,
|
|
437
|
+
});
|
|
438
|
+
const ctx = { project, db, queueManager, chatManager, setupManager, proposalManager, agentRefineManager, fileSummaryManager, specLauncherManager, ticketWatcher, browserCaptureManager, broadcast: boundBroadcast, railJobs };
|
|
439
|
+
this._contexts.set(project.id, ctx);
|
|
440
|
+
return ctx;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
exports.ProjectRegistry = ProjectRegistry;
|