farming-code 2.2.23 → 2.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/README.zh_cn.md +9 -2
- package/THIRD_PARTY_NOTICES.md +3 -0
- package/backend/acp-runtime.js +15 -1
- package/backend/agent-manager.js +1054 -94
- package/backend/atomic-json-store.js +37 -0
- package/backend/cli-agents.js +9 -7
- package/backend/config-manager.js +167 -58
- package/backend/control-api.js +2 -1
- package/backend/farming-agent-bootstrap.js +49 -0
- package/backend/farming-agent-bootstrap.zh_cn.md +5 -0
- package/backend/farming-app-cli.js +9 -2
- package/backend/farming-cli.js +55 -0
- package/backend/farming-session-store.js +92 -89
- package/backend/main-agent-skills.js +17 -0
- package/backend/native-pty-host-client.js +99 -7
- package/backend/native-pty-host-path.js +20 -0
- package/backend/native-pty-host.js +6 -5
- package/backend/preview-session-manager.js +68 -0
- package/backend/provider-adapters.js +44 -5
- package/backend/review-session-store.js +32 -25
- package/backend/review-state-store.js +13 -14
- package/backend/run-history-store.js +13 -16
- package/backend/server.js +103 -78
- package/backend/storage-layout.js +20 -0
- package/backend/workspace-file-router.js +171 -6
- package/backend/workspace-file-service.js +19 -0
- package/backend/workspace-root-registry.js +6 -4
- package/dist/assets/App-CM7Cy-l4.css +1 -0
- package/dist/assets/App-CPG4WcjO.js +658 -0
- package/dist/assets/{FileEditorMarkdownPreview-KbnE8VC8.js → FileEditorMarkdownPreview-DYOMm-b1.js} +5 -5
- package/dist/assets/FileEditorPane-DXXq82aM.js +2 -0
- package/dist/assets/IconGlyphs-DrdPjYXr.js +1 -0
- package/dist/assets/ProjectFilesSection-CP66XVPl.js +12 -0
- package/dist/assets/{ReviewPage-L1vh1Ggs.js → ReviewPage-w21MEPD6.js} +1 -1
- package/dist/assets/{abnfDiagram-VRR7QNED-nnglrXFi.js → abnfDiagram-VRR7QNED-BY1qwq8A.js} +1 -1
- package/dist/assets/api-w2x5QfxB.js +1 -0
- package/dist/assets/{arc-CWoVlxJw.js → arc-DgZRAlwj.js} +1 -1
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BEXMaFfY.js → architectureDiagram-ZJ3FMSHR-jFn144od.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-1mCezSBk.js → blockDiagram-677ZJIJ3-BmRjlV0H.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-DhTiI6Uv.js → c4Diagram-LMCZKHZV-DUKul6tT.js} +1 -1
- package/dist/assets/{workspace-editor-monaco-DLlws5Ig.js → channel-CI9j3QFD.js} +1 -1
- package/dist/assets/chunk-2Q5K7J3B-87UnWaoh.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-CCdsKd73.js → chunk-32BRIVSS-rGVu23o5.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-Gncjk4LF.js → chunk-52WLFC77-CvFDKgbB.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-Dlw7AXWp.js → chunk-5VM5RSS4-CFgnRW1C.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-ZBRhjLOh.js → chunk-7BUUIJ7U-Cp7bqW6s.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-CiDVUP82.js → chunk-C7G6YPKG-BIS1gjZO.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-z6gXP2_N.js → chunk-EX3LRPZG-BKG-cR9j.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-DMZBccQa.js → chunk-FWX5IMBZ-B8PsTr8a.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-D8tIeoPk.js → chunk-HOUHSVGY-BHFOAiXT.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-b6oQ2Q17.js → chunk-ICXQ74PX-CvLE1J9X.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DSyBRaRG.js → chunk-JWPE2WC7-D8misks7.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-DAVH_p2a.js → chunk-MOJQB5TN-D-oNgSNH.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-DxoiMCI-.js → chunk-OGEWGWER-C2N-la9e.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-NsOWh7HM.js → chunk-PUDLZKDR-BwI3Jz8q.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Di4H7L21.js → chunk-Q4XR5HBZ-BuqGfsXA.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-CZA9pvFX.js → chunk-RYQCIY6F-Bq4XZcGt.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-DttpZg9Y.js → chunk-V7JOEXUC-QZLzdTTJ.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-Cb0-kQ9g.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-D-Fmtd4Z.js → chunk-VR4S4FIN-DcZTpML_.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-CUxMtfK2.js → chunk-WYO6CB5R-DCU8wuny.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-BZAC1Krv.js +1 -0
- package/dist/assets/{chunk-ZGVPDNZ5-CoV2QEl0.js → chunk-ZGVPDNZ5-B7r85QbY.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-DncwlQQc.js → chunk-ZIRB5QZD-BgEnDWhQ.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DcvGOuvi.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DDYUSofQ.js +1 -0
- package/dist/assets/code-dark-BDjwj7Um.css +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-BNIAz0nN.js → cose-bilkent-JH36ORCC-CThXS2qG.js} +1 -1
- package/dist/assets/{cssMode-DDWxTPm_.js → cssMode-Bdg5RpcJ.js} +1 -1
- package/dist/assets/{cynefinDiagram-TSTJHNR4-0xPI92Lg.js → cynefinDiagram-TSTJHNR4-DxBgzw25.js} +1 -1
- package/dist/assets/{dagre-DXlcHgr3.js → dagre-BM-GvGUZ.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-DfuMG4gU.js → dagre-VKFMJZFB-B7UCRmxR.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-CT00bLZ6.js → diagram-FQU43EPY-CeL2DwKx.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-Xbh7zXUx.js → diagram-G47NLZAW-BEirglCC.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-SRDVPfn7.js → diagram-NH7WQ7WH-C6wcI-Rl.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CQRli4Np.js → diagram-OA4YK3LP-DpM-XXtJ.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-DMf17WQi.js → diagram-WEI45ONY-BQyaut9k.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-DhpFkgJ5.js → ebnfDiagram-CCIWWBDH-UmAXsUhr.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-1IwxWmJo.js → erDiagram-Q63AITRT-CdYLEOch.js} +1 -1
- package/dist/assets/file-icons-BOlcJ0ZF.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-CO-z9-tq.js +1 -0
- package/dist/assets/{freemarker2-QBsTERH-.js → freemarker2-DfMDJfnE.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-BNCdfyr1.js → ganttDiagram-NO4QXBWP-DgSUNdUB.js} +1 -1
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-pbyWZuiX.js → gitGraphDiagram-IHSO6WYX-DjwjtRtF.js} +1 -1
- package/dist/assets/{handlebars-CuoxPo5A.js → handlebars-BEdPtzMT.js} +1 -1
- package/dist/assets/{html-gX5PEu0Q.js → html-B1fPb1QD.js} +1 -1
- package/dist/assets/html2canvas-DsczWxBa.js +5 -0
- package/dist/assets/{htmlMode-DIWUbUxd.js → htmlMode-CY2ZjHxH.js} +1 -1
- package/dist/assets/{index-DhTUO8DA.js → index-BzQO3pUr.js} +2 -2
- package/dist/assets/{infoDiagram-FWYZ7A6U-BcTOgDbe.js → infoDiagram-FWYZ7A6U-Bi9076l2.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-DCdvGKrn.js → ishikawaDiagram-FXEZZL3T-DaMaNZN7.js} +1 -1
- package/dist/assets/{javascript-BYKGIUGs.js → javascript-BV2OsWA0.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-BZ-1q_IT.js → journeyDiagram-5HDEW3XC-CfDy69EZ.js} +1 -1
- package/dist/assets/{jsonMode-AFmQQP6u.js → jsonMode-zd07aeuX.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-BIgejCjj.js → kanban-definition-HUTT4EX6-XFvZ722B.js} +1 -1
- package/dist/assets/{line-CfptFMmX.js → line-BXK9PKLn.js} +1 -1
- package/dist/assets/{linear-Dld3_ERu.js → linear-CULvmq2Z.js} +1 -1
- package/dist/assets/{liquid-DBIl-f0z.js → liquid-BParI24X.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-DK6tqicV.js → lspLanguageFeatures-BzredkoV.js} +1 -1
- package/dist/assets/main-BlVUXfxa.css +1 -0
- package/dist/assets/{map-LZWWoeWa.js → map-C9Qw9eWh.js} +1 -1
- package/dist/assets/{mdx-DS-bVtZN.js → mdx-vGzUJN98.js} +1 -1
- package/dist/assets/{mermaid.core-gSpX30pV.js → mermaid.core-CzazaIKr.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BKBaI4LW.js → mindmap-definition-LN4V7U3C-Uoff7hZ3.js} +1 -1
- package/dist/assets/{monaco.contribution-BXz-lfFB.js → monaco.contribution-BmaeBQEc.js} +2 -2
- package/dist/assets/{ordinal-BLrOss5K.js → ordinal-r6pIwRdZ.js} +1 -1
- package/dist/assets/{pegDiagram-2B236MQR-sBvDY3VX.js → pegDiagram-2B236MQR-CCBiHQjk.js} +1 -1
- package/dist/assets/{pieDiagram-ENE6RG2P-DWlWcu08.js → pieDiagram-ENE6RG2P-D61s7l75.js} +1 -1
- package/dist/assets/{python-C93q3xXz.js → python-CUwdLgsI.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-DZutUd3J.js → quadrantDiagram-ABIIQ3AL-D_CWk2DQ.js} +1 -1
- package/dist/assets/{railroadDiagram-RFXS5EU6-DQb3lXGM.js → railroadDiagram-RFXS5EU6-CdlCHtxN.js} +1 -1
- package/dist/assets/{razor-CBifNGXO.js → razor-BScebUxU.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-DqFGXu2e.js → requirementDiagram-TGXJPOKE-BLpHtkoC.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-d7ECahnO.js → sankeyDiagram-HTMAVEWB-CkhYZN2j.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-DdsbKqct.js → sequenceDiagram-DBY2YBRQ-8bploKJl.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-daTB6OcF.js → sizeCapture-X5ZJPWSS-DtSdkS0d.js} +1 -1
- package/dist/assets/{src-WBW1QxJt.js → src-6yeq6WBA.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-P6iSrgwR.js → stateDiagram-2N3HPSRC-DfmVGpfA.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-B2c9CQ-J.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BGnZJx1M.js → swimlanes-5IMT3BWC-DRLk2zRF.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-B7_APh_h.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-rA-r3aUR.js → timeline-definition-FHXFAJF6-Cngfy588.js} +1 -1
- package/dist/assets/{tsMode-B0oUTcXQ.js → tsMode-DzUAibXK.js} +1 -1
- package/dist/assets/{typescript-KJKfYO7K.js → typescript-D9EOeM7N.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-DiVKUjA9.js → vennDiagram-L72KCM5P-DeJn63Lq.js} +1 -1
- package/dist/assets/{wardleyDiagram-EHGQE667-Cfxh7UOn.js → wardleyDiagram-EHGQE667-BH1nzy77.js} +1 -1
- package/dist/assets/{workers-BSQRIkqa.js → workers-DAiomYZM.js} +1 -1
- package/dist/assets/workspace-editor-model-CSGCl21x.js +1 -0
- package/dist/assets/workspace-editor-monaco-CFEfFNcA.js +1 -0
- package/dist/assets/{workspace-editor-monaco-BIpqcWf1.js → workspace-editor-monaco-tXA-udGx.js} +3 -3
- package/dist/assets/workspace-view-state-BS_V8JVs.js +7 -0
- package/dist/assets/{xml-C8FAcN6j.js → xml-wWl1dhkQ.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG--hmryQeL.js → xychartDiagram-FW5EYKEG-SkO2prCU.js} +1 -1
- package/dist/assets/{yaml-BQ4NrRhG.js → yaml-Dc2WDaOZ.js} +1 -1
- package/dist/crt-markdown-renderer.js +46 -46
- package/dist/index.html +1 -1
- package/extensions/browser/backend/agent-capability.js +55 -0
- package/extensions/browser/backend/browser-mcp-server.js +269 -0
- package/extensions/browser/backend/browser-resource-manager.js +524 -0
- package/extensions/browser/backend/browser-resource-store.js +149 -0
- package/extensions/browser/backend/browser-router.js +128 -0
- package/extensions/browser/backend/cdp-browser-runtime.js +648 -0
- package/extensions/browser/backend/cdp-client.js +167 -0
- package/extensions/browser/backend/executable-discovery.js +91 -0
- package/extensions/browser/backend/farming-browser-client.js +83 -0
- package/extensions/browser/backend/index.js +7 -0
- package/extensions/browser/bin/farming-browser +117 -0
- package/extensions/browser/frontend/BrowserSidebarPortals.tsx +362 -0
- package/extensions/browser/frontend/BrowserViewer.tsx +329 -0
- package/extensions/browser/frontend/browser-resource-state.ts +60 -0
- package/extensions/browser/frontend/browser.css +516 -0
- package/extensions/browser/frontend/types.ts +25 -0
- package/extensions/browser/frontend/useBrowserResources.ts +151 -0
- package/frontend/session-bridge.js +7 -6
- package/frontend/skins/crt/app.js +64 -4
- package/package.json +18 -13
- package/shared/browser-protocol.js +1 -1
- package/dist/assets/App-BbNBDA__.js +0 -210
- package/dist/assets/App-BrP-ENHg.css +0 -1
- package/dist/assets/FileEditorPane-5_HUejjd.js +0 -2
- package/dist/assets/IconGlyphs-C2WFcoJS.js +0 -1
- package/dist/assets/ProjectFilesSection-C1RAJWOE.js +0 -12
- package/dist/assets/api-D8nyOEbz.js +0 -1
- package/dist/assets/channel-BVWNatUB.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-d5WWh8jo.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-UHNr_yhX.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-BBXwjhUx.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Db0ib5iE.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-Bkf69XF9.js +0 -1
- package/dist/assets/code-dark-BKtvf0Xc.css +0 -1
- package/dist/assets/file-icons-CHWt5nSy.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DYFo2xmB.js +0 -1
- package/dist/assets/main-XMXgyJJt.css +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-DIYSf_qh.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BIkrlKrZ.js +0 -8
- package/dist/assets/workspace-editor-model-D0Im34S5.js +0 -1
- package/dist/assets/workspace-view-state-BqB4HM7r.js +0 -7
- /package/dist/assets/{abap-Cc5D5h5i.js → abap-CtX5nWyX.js} +0 -0
- /package/dist/assets/{apex-BKopwLmx.js → apex-DQJRAHwc.js} +0 -0
- /package/dist/assets/{array-HeX70jSN.js → array-BTwzYU0x.js} +0 -0
- /package/dist/assets/{azcli-DI-C34WA.js → azcli-9SMrOQ4q.js} +0 -0
- /package/dist/assets/{bat-Cbp6u42z.js → bat-CBGLUsw1.js} +0 -0
- /package/dist/assets/{bicep-4QA1jTCM.js → bicep-pDx8da1v.js} +0 -0
- /package/dist/assets/{cameligo-Dda_adPs.js → cameligo-hZV3vQ6_.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-Di0sYzi1.js → chunk-Y2CYZVJY-BYi0W5ea.js} +0 -0
- /package/dist/assets/{clojure-CvY8A83L.js → clojure-BhCwU3gq.js} +0 -0
- /package/dist/assets/{coffee-4LX2Sv8A.js → coffee-BVB1PsgH.js} +0 -0
- /package/dist/assets/{core-B9MwRjDE.js → core-vPkV8P_m.js} +0 -0
- /package/dist/assets/{cpp-D4AzSV28.js → cpp-eTjuiNPq.js} +0 -0
- /package/dist/assets/{csharp-C4nWN4Yd.js → csharp-1kP-kKZT.js} +0 -0
- /package/dist/assets/{csp-CiEaaS5Z.js → csp-C_iQqIes.js} +0 -0
- /package/dist/assets/{css-DXxBRsbk.js → css-CxOs7IfP.js} +0 -0
- /package/dist/assets/{cypher-DOMzqyFA.js → cypher-Cd-a9Y82.js} +0 -0
- /package/dist/assets/{cytoscape.esm-Cl8iC3D7.js → cytoscape.esm-OLojuicg.js} +0 -0
- /package/dist/assets/{dart-BWS7MXt_.js → dart-whhXpexn.js} +0 -0
- /package/dist/assets/{defaultLocale-GJwWH1Jr.js → defaultLocale-CPimVhfE.js} +0 -0
- /package/dist/assets/{dist-ClAL-Tv5.js → dist-CLPYXg1u.js} +0 -0
- /package/dist/assets/{dockerfile-Baf4U3xT.js → dockerfile-DibBi8b6.js} +0 -0
- /package/dist/assets/{ecl-CT7udlkQ.js → ecl-DlF1KdoW.js} +0 -0
- /package/dist/assets/{editor.api2-B9h6iFPK.js → editor.api2-D74ufkbr.js} +0 -0
- /package/dist/assets/{elixir-CIbAZw5l.js → elixir-CHQ8uFT3.js} +0 -0
- /package/dist/assets/{flow9-Dqiw45WV.js → flow9-8nUnVKk1.js} +0 -0
- /package/dist/assets/{fsharp-E8E2L9jU.js → fsharp-DNZNZyEE.js} +0 -0
- /package/dist/assets/{go-CouVSN4D.js → go-_kPJjNc_.js} +0 -0
- /package/dist/assets/{graphlib-CbSvZcZU.js → graphlib-CBGF9gA9.js} +0 -0
- /package/dist/assets/{graphql-a6h6h5-t.js → graphql-4HCNVt5g.js} +0 -0
- /package/dist/assets/{hcl-vso3e6N-.js → hcl-C87ymY0o.js} +0 -0
- /package/dist/assets/{ini-SwZZkotR.js → ini-BYrrGNTc.js} +0 -0
- /package/dist/assets/{init-BPLPMQ3Y.js → init-8_PCa3LO.js} +0 -0
- /package/dist/assets/{java-CtRLC4_3.js → java-B211rJbk.js} +0 -0
- /package/dist/assets/{julia-CuJWFKQH.js → julia-DVPsRtBm.js} +0 -0
- /package/dist/assets/{katex-C8DPyI6s.js → katex-C2iYad0m.js} +0 -0
- /package/dist/assets/{kotlin-B_kBhsre.js → kotlin-BYyNerjp.js} +0 -0
- /package/dist/assets/{less-CtrHIfz3.js → less-EC9UblGE.js} +0 -0
- /package/dist/assets/{lexon-yVt1pJLu.js → lexon-B1yuUdqW.js} +0 -0
- /package/dist/assets/{lua-prOwgJ4U.js → lua-Bo6GFzxT.js} +0 -0
- /package/dist/assets/{m3-DhrdTQ84.js → m3-C-Y9cBVI.js} +0 -0
- /package/dist/assets/{markdown-DoI5HwSM.js → markdown-BHu-wLbe.js} +0 -0
- /package/dist/assets/{mermaid-parser.core-BQtepoLd.js → mermaid-parser.core-IxcGtNYG.js} +0 -0
- /package/dist/assets/{mips-Dye5jsBU.js → mips-Dkds26rX.js} +0 -0
- /package/dist/assets/{msdax-TkNOyIL8.js → msdax-PU4g-8_g.js} +0 -0
- /package/dist/assets/{mysql-CEc-RKZF.js → mysql-fPpuGpS7.js} +0 -0
- /package/dist/assets/{objective-c-CqqCsQz0.js → objective-c-Wy1e5JUf.js} +0 -0
- /package/dist/assets/{pascal-DO_pj8yg.js → pascal-BIXwvrqU.js} +0 -0
- /package/dist/assets/{pascaligo-1cbdZdF3.js → pascaligo-DwR0AtL_.js} +0 -0
- /package/dist/assets/{path-YdFzr2W6.js → path-BxQuywGl.js} +0 -0
- /package/dist/assets/{perl-B_N3PYfC.js → perl-CGHAl8my.js} +0 -0
- /package/dist/assets/{pgsql-9iYk1FQ7.js → pgsql-B91M73E2.js} +0 -0
- /package/dist/assets/{php-rO2sgoUM.js → php-C70ttrCx.js} +0 -0
- /package/dist/assets/{pla-Cbgv60kq.js → pla-BNrXaRh0.js} +0 -0
- /package/dist/assets/{postiats-y6xrhy_M.js → postiats-Dv2IAZR9.js} +0 -0
- /package/dist/assets/{powerquery-BaD8gWNE.js → powerquery-CkY5Wq7J.js} +0 -0
- /package/dist/assets/{powershell-BMhG4JVe.js → powershell-uGIYLU3C.js} +0 -0
- /package/dist/assets/{protobuf-CdOP5kN3.js → protobuf-CavfmJu-.js} +0 -0
- /package/dist/assets/{pug-Ck60hNF9.js → pug-Drqnyitx.js} +0 -0
- /package/dist/assets/{qrcode-DV-_rjU8.js → qrcode-7uGsTEmi.js} +0 -0
- /package/dist/assets/{qsharp-BcaKFfP-.js → qsharp-C7yF-Dti.js} +0 -0
- /package/dist/assets/{r-rFNes0iK.js → r-HXLGP0_-.js} +0 -0
- /package/dist/assets/{redis-DkpQ3K6G.js → redis-C4y6mf2p.js} +0 -0
- /package/dist/assets/{redshift-Di9N5TI3.js → redshift-DdQrFPrv.js} +0 -0
- /package/dist/assets/{restructuredtext-By5ZzLt6.js → restructuredtext-CBrf2PNj.js} +0 -0
- /package/dist/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
- /package/dist/assets/{ruby-fF5zGiLp.js → ruby-CVtMoX2B.js} +0 -0
- /package/dist/assets/{rust-C5b3AYY6.js → rust-Ckq4sbMP.js} +0 -0
- /package/dist/assets/{sb-CD07UNRs.js → sb-er66OpE3.js} +0 -0
- /package/dist/assets/{scala-jtn1ip9G.js → scala-BdWZz-hH.js} +0 -0
- /package/dist/assets/{scheme-C4vqMkn_.js → scheme-kTV_s2kP.js} +0 -0
- /package/dist/assets/{scss-I4Glxjbz.js → scss-Bymy2VJQ.js} +0 -0
- /package/dist/assets/{shell-DubUcuns.js → shell-bwEP1LQ1.js} +0 -0
- /package/dist/assets/{solidity-CNy2KSl2.js → solidity-DCddeBgL.js} +0 -0
- /package/dist/assets/{sophia-D9_URt84.js → sophia-BMN3AQig.js} +0 -0
- /package/dist/assets/{sparql-DviXpm4C.js → sparql-CSXOLjzi.js} +0 -0
- /package/dist/assets/{sql-vDRbAZgK.js → sql-COg8ewmK.js} +0 -0
- /package/dist/assets/{st-CnpnRqA7.js → st-CIaZtBS_.js} +0 -0
- /package/dist/assets/{swift-D_g8Ganz.js → swift-DXiOhUHu.js} +0 -0
- /package/dist/assets/{systemverilog-OuZa5h1M.js → systemverilog-BTDE6Dr2.js} +0 -0
- /package/dist/assets/{tcl-DBm9ucsV.js → tcl-B0zy9NvV.js} +0 -0
- /package/dist/assets/{twig-BRzEqX5Y.js → twig-D594l4Z1.js} +0 -0
- /package/dist/assets/{typespec-D4ZgGeX8.js → typespec-XKVjaPqo.js} +0 -0
- /package/dist/assets/{useWorkspaceMenuKeyboard-Brws6Ar9.js → useWorkspaceMenuKeyboard-Bpy_s69Z.js} +0 -0
- /package/dist/assets/{vb-DcP4s6WS.js → vb-B2wYoKRV.js} +0 -0
- /package/dist/assets/{wgsl-CnRJ_QUf.js → wgsl-D0Yf2LbK.js} +0 -0
- /package/dist/assets/{workspace-working-copy-D8-s_Sgh.js → workspace-working-copy-C3FSR3N6.js} +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
function atomicWriteJson(file, value, options = {}) {
|
|
6
|
+
const fileSystem = options.fileSystem || fs;
|
|
7
|
+
const temporaryFile = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
8
|
+
const suffix = options.trailingNewline ? '\n' : '';
|
|
9
|
+
let descriptor = null;
|
|
10
|
+
|
|
11
|
+
fileSystem.mkdirSync(path.dirname(file), { recursive: true });
|
|
12
|
+
try {
|
|
13
|
+
descriptor = fileSystem.openSync(temporaryFile, 'wx', options.mode);
|
|
14
|
+
fileSystem.writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}${suffix}`, 'utf8');
|
|
15
|
+
fileSystem.fdatasyncSync(descriptor);
|
|
16
|
+
fileSystem.closeSync(descriptor);
|
|
17
|
+
descriptor = null;
|
|
18
|
+
fileSystem.renameSync(temporaryFile, file);
|
|
19
|
+
} finally {
|
|
20
|
+
if (descriptor !== null) {
|
|
21
|
+
try {
|
|
22
|
+
fileSystem.closeSync(descriptor);
|
|
23
|
+
} catch {
|
|
24
|
+
// Preserve the original write failure.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
fileSystem.unlinkSync(temporaryFile);
|
|
29
|
+
} catch {
|
|
30
|
+
// A successful rename already removed the temporary path.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
atomicWriteJson,
|
|
37
|
+
};
|
package/backend/cli-agents.js
CHANGED
|
@@ -49,7 +49,8 @@ const CLI_AGENTS = [
|
|
|
49
49
|
permissions: {
|
|
50
50
|
supportsDangerousSkip: true,
|
|
51
51
|
dangerousSkipArgs: ['--dangerously-skip-permissions']
|
|
52
|
-
}
|
|
52
|
+
},
|
|
53
|
+
systemPromptArg: '--append-system-prompt'
|
|
53
54
|
},
|
|
54
55
|
{
|
|
55
56
|
name: 'bash',
|
|
@@ -459,12 +460,13 @@ function resolveLaunchCommand(command, options = {}) {
|
|
|
459
460
|
launchArgs.unshift('--permission-mode', claudePermissionMode);
|
|
460
461
|
}
|
|
461
462
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
463
|
+
const systemPrompt = [options.farmingSystemPrompt, options.mainAgentSystemPrompt]
|
|
464
|
+
.filter(value => typeof value === 'string' && value.trim())
|
|
465
|
+
.join('\n\n');
|
|
466
|
+
if (systemPrompt && spec && typeof spec.systemPromptArg === 'string') {
|
|
467
|
+
launchArgs.push(spec.systemPromptArg, systemPrompt);
|
|
468
|
+
} else if (systemPrompt && spec?.name === 'codex') {
|
|
469
|
+
launchArgs.unshift('-c', `developer_instructions=${JSON.stringify(systemPrompt)}`);
|
|
468
470
|
}
|
|
469
471
|
|
|
470
472
|
return {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
|
+
const { atomicWriteJson } = require('./atomic-json-store');
|
|
4
5
|
const { ensureMainAgentSkillFiles } = require('./main-agent-skills');
|
|
6
|
+
const { ensureFarmingAgentBootstrapFile } = require('./farming-agent-bootstrap');
|
|
5
7
|
const { normalizeClaudeModelValue } = require('./claude-settings');
|
|
6
8
|
const { isTemporaryProviderSessionId } = require('./provider-session-id');
|
|
7
9
|
const { FarmingSessionStore, MAX_MAIN_PAGE_SESSION_KEYS } = require('./farming-session-store');
|
|
@@ -68,6 +70,8 @@ const DEFAULT_CRT_TERMINAL_FONT_SIZE = 15;
|
|
|
68
70
|
const MIN_CRT_TERMINAL_FONT_SIZE = 10;
|
|
69
71
|
const MAX_CRT_TERMINAL_FONT_SIZE = 20;
|
|
70
72
|
const MAX_INSTANCE_NAME_LENGTH = 80;
|
|
73
|
+
const MAX_PROJECT_OPERATIONS = 32;
|
|
74
|
+
const PROJECT_OPERATION_ID_PATTERN = /^[A-Za-z0-9._:-]{1,160}$/;
|
|
71
75
|
|
|
72
76
|
const PERSISTED_SETTING_KEYS = new Set([
|
|
73
77
|
'workspace',
|
|
@@ -76,12 +80,14 @@ const PERSISTED_SETTING_KEYS = new Set([
|
|
|
76
80
|
'projectWorkspaces',
|
|
77
81
|
'pinnedProjectWorkspaces',
|
|
78
82
|
'projectNames',
|
|
83
|
+
'projectOperations',
|
|
79
84
|
'instanceName',
|
|
80
85
|
'theme',
|
|
81
86
|
'appearance',
|
|
82
87
|
'language',
|
|
83
88
|
'heartbeatInterval',
|
|
84
89
|
'dangerouslySkipAgentPermissionsByDefault',
|
|
90
|
+
'browserExtensionEnabled',
|
|
85
91
|
'crtSkinEffectsEnabled',
|
|
86
92
|
'crtDynamicHeatEnabled',
|
|
87
93
|
'crtTerminalFontSize',
|
|
@@ -113,8 +119,8 @@ function cloneAgentHomes(agentHomes) {
|
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
class ConfigManager {
|
|
116
|
-
constructor() {
|
|
117
|
-
this.farmingDir = storageLayout.farmingConfigDir();
|
|
122
|
+
constructor(options = {}) {
|
|
123
|
+
this.farmingDir = options.configDir || storageLayout.farmingConfigDir();
|
|
118
124
|
this.settingsFile = storageLayout.settingsFile(this.farmingDir);
|
|
119
125
|
this.sessionStore = new FarmingSessionStore(this.farmingDir, {
|
|
120
126
|
normalizeMainPageSessionKeys: keys => this.normalizeMainPageSessionKeys(keys),
|
|
@@ -122,6 +128,7 @@ class ConfigManager {
|
|
|
122
128
|
this.runHistoryStore = new RunHistoryStore(this.farmingDir, {
|
|
123
129
|
normalizeTaskHistory: entries => this.normalizeTaskHistory(entries),
|
|
124
130
|
});
|
|
131
|
+
this.writeJson = typeof options.writeJson === 'function' ? options.writeJson : atomicWriteJson;
|
|
125
132
|
this.settings = null;
|
|
126
133
|
}
|
|
127
134
|
|
|
@@ -221,7 +228,7 @@ class ConfigManager {
|
|
|
221
228
|
const expanded = this.expandWorkspacePath(entry);
|
|
222
229
|
if (!expanded) continue;
|
|
223
230
|
const resolved = path.resolve(expanded);
|
|
224
|
-
if (
|
|
231
|
+
if (this.isInternalWorkspace(resolved)) continue;
|
|
225
232
|
let canonical = resolved;
|
|
226
233
|
try {
|
|
227
234
|
canonical = fs.realpathSync(resolved);
|
|
@@ -305,12 +312,14 @@ class ConfigManager {
|
|
|
305
312
|
projectWorkspaces: [],
|
|
306
313
|
pinnedProjectWorkspaces: [],
|
|
307
314
|
projectNames: {},
|
|
315
|
+
projectOperations: {},
|
|
308
316
|
instanceName: '',
|
|
309
317
|
theme: 'terminal',
|
|
310
318
|
appearance: 'system',
|
|
311
319
|
language: 'en',
|
|
312
320
|
heartbeatInterval: 1000,
|
|
313
321
|
dangerouslySkipAgentPermissionsByDefault: false,
|
|
322
|
+
browserExtensionEnabled: false,
|
|
314
323
|
crtSkinEffectsEnabled: true,
|
|
315
324
|
crtDynamicHeatEnabled: false,
|
|
316
325
|
crtTerminalFontSize: DEFAULT_CRT_TERMINAL_FONT_SIZE,
|
|
@@ -329,7 +338,7 @@ class ConfigManager {
|
|
|
329
338
|
codexModelPreset: 'gpt-5.5:xhigh',
|
|
330
339
|
version: '2'
|
|
331
340
|
};
|
|
332
|
-
|
|
341
|
+
this.writeSettingsFile(defaultSettings);
|
|
333
342
|
console.log('Created default settings:', this.settingsFile);
|
|
334
343
|
}
|
|
335
344
|
|
|
@@ -341,12 +350,14 @@ class ConfigManager {
|
|
|
341
350
|
projectWorkspaces: [],
|
|
342
351
|
pinnedProjectWorkspaces: [],
|
|
343
352
|
projectNames: {},
|
|
353
|
+
projectOperations: {},
|
|
344
354
|
instanceName: '',
|
|
345
355
|
theme: 'terminal',
|
|
346
356
|
appearance: 'system',
|
|
347
357
|
language: 'en',
|
|
348
358
|
heartbeatInterval: 1000,
|
|
349
359
|
dangerouslySkipAgentPermissionsByDefault: false,
|
|
360
|
+
browserExtensionEnabled: false,
|
|
350
361
|
crtSkinEffectsEnabled: true,
|
|
351
362
|
crtDynamicHeatEnabled: false,
|
|
352
363
|
crtTerminalFontSize: DEFAULT_CRT_TERMINAL_FONT_SIZE,
|
|
@@ -391,6 +402,7 @@ class ConfigManager {
|
|
|
391
402
|
this.settings.projectWorkspaces = this.normalizeProjectWorkspaces(this.settings.projectWorkspaces);
|
|
392
403
|
this.settings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(this.settings.pinnedProjectWorkspaces);
|
|
393
404
|
this.settings.projectNames = this.normalizeProjectNames(this.settings.projectNames);
|
|
405
|
+
this.settings.projectOperations = this.normalizeProjectOperations(this.settings.projectOperations);
|
|
394
406
|
this.settings.instanceName = this.normalizeInstanceName(this.settings.instanceName);
|
|
395
407
|
this.settings.agentHomes = this.normalizeAgentHomes(this.settings.agentHomes);
|
|
396
408
|
if (this.settings.updateUrl === LEGACY_DEFAULT_UPDATE_URL || this.settings.updateUrl === API_DEFAULT_UPDATE_URL) {
|
|
@@ -407,20 +419,22 @@ class ConfigManager {
|
|
|
407
419
|
this.runHistoryStore.init({ legacyTaskHistory });
|
|
408
420
|
this.settings.appearance = this.normalizeAppearance(this.settings.appearance);
|
|
409
421
|
this.settings.language = this.normalizeLanguage(this.settings.language);
|
|
422
|
+
this.settings.browserExtensionEnabled = this.settings.browserExtensionEnabled === true;
|
|
410
423
|
this.settings.crtSkinEffectsEnabled = this.settings.crtSkinEffectsEnabled !== false;
|
|
411
424
|
this.settings.crtDynamicHeatEnabled = this.settings.crtDynamicHeatEnabled === true;
|
|
412
425
|
this.settings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(this.settings.crtTerminalFontSize);
|
|
413
426
|
this.normalizeAgentLaunchSettings(launchRawSettings);
|
|
414
427
|
this.pruneUnknownSettings();
|
|
415
428
|
ensureMainAgentSkillFiles(this.farmingDir);
|
|
429
|
+
ensureFarmingAgentBootstrapFile(this.farmingDir);
|
|
416
430
|
this.writeSettingsFile();
|
|
417
431
|
console.log('Loaded settings:', this.settings);
|
|
418
432
|
}
|
|
419
433
|
|
|
420
|
-
pruneUnknownSettings() {
|
|
421
|
-
for (const key of Object.keys(
|
|
434
|
+
pruneUnknownSettings(settings = this.settings) {
|
|
435
|
+
for (const key of Object.keys(settings || {})) {
|
|
422
436
|
if (!PERSISTED_SETTING_KEYS.has(key)) {
|
|
423
|
-
delete
|
|
437
|
+
delete settings[key];
|
|
424
438
|
}
|
|
425
439
|
}
|
|
426
440
|
}
|
|
@@ -498,16 +512,59 @@ class ConfigManager {
|
|
|
498
512
|
return normalized;
|
|
499
513
|
}
|
|
500
514
|
|
|
515
|
+
normalizeProjectOperations(projectOperations) {
|
|
516
|
+
if (!projectOperations || typeof projectOperations !== 'object' || Array.isArray(projectOperations)) return {};
|
|
517
|
+
const entries = Object.entries(projectOperations)
|
|
518
|
+
.filter(([id, operation]) => (
|
|
519
|
+
PROJECT_OPERATION_ID_PATTERN.test(id)
|
|
520
|
+
&& operation
|
|
521
|
+
&& typeof operation === 'object'
|
|
522
|
+
&& ['create-worktree', 'delete-worktree'].includes(operation.type)
|
|
523
|
+
&& ['pending', 'unknown', 'succeeded', 'failed', 'blocked'].includes(operation.state)
|
|
524
|
+
))
|
|
525
|
+
.sort((left, right) => (Number(right[1].updatedAt) || 0) - (Number(left[1].updatedAt) || 0))
|
|
526
|
+
.map(([id, operation]) => [id, {
|
|
527
|
+
id,
|
|
528
|
+
type: operation.type,
|
|
529
|
+
state: operation.state,
|
|
530
|
+
signature: typeof operation.signature === 'string' ? operation.signature.slice(0, 128) : '',
|
|
531
|
+
request: operation.request && typeof operation.request === 'object'
|
|
532
|
+
? JSON.parse(JSON.stringify(operation.request))
|
|
533
|
+
: {},
|
|
534
|
+
result: operation.result && typeof operation.result === 'object'
|
|
535
|
+
? JSON.parse(JSON.stringify(operation.result))
|
|
536
|
+
: null,
|
|
537
|
+
error: typeof operation.error === 'string' ? operation.error.slice(0, 2000) : '',
|
|
538
|
+
startedAt: Number(operation.startedAt) || 0,
|
|
539
|
+
updatedAt: Number(operation.updatedAt) || 0,
|
|
540
|
+
finishedAt: Number(operation.finishedAt) || null,
|
|
541
|
+
}]);
|
|
542
|
+
const unresolved = entries.filter(([, operation]) => (
|
|
543
|
+
['pending', 'unknown', 'blocked'].includes(operation.state)
|
|
544
|
+
));
|
|
545
|
+
const terminal = entries.filter(([, operation]) => (
|
|
546
|
+
!['pending', 'unknown', 'blocked'].includes(operation.state)
|
|
547
|
+
));
|
|
548
|
+
return Object.fromEntries([
|
|
549
|
+
...unresolved,
|
|
550
|
+
...terminal.slice(0, Math.max(0, MAX_PROJECT_OPERATIONS - unresolved.length)),
|
|
551
|
+
]);
|
|
552
|
+
}
|
|
553
|
+
|
|
501
554
|
setProjectName(workspace, name) {
|
|
502
555
|
const normalized = this.normalizeProjectNames({ [workspace]: name });
|
|
503
556
|
const entry = Object.entries(normalized)[0];
|
|
504
557
|
if (!entry) throw new Error('Project workspace and name are required');
|
|
505
558
|
const [normalizedWorkspace, normalizedName] = entry;
|
|
506
|
-
|
|
507
|
-
...this.settings
|
|
508
|
-
|
|
559
|
+
const nextSettings = {
|
|
560
|
+
...this.settings,
|
|
561
|
+
projectNames: {
|
|
562
|
+
...this.settings.projectNames,
|
|
563
|
+
[normalizedWorkspace]: normalizedName,
|
|
564
|
+
},
|
|
509
565
|
};
|
|
510
|
-
this.writeSettingsFile();
|
|
566
|
+
this.writeSettingsFile(nextSettings);
|
|
567
|
+
this.settings = nextSettings;
|
|
511
568
|
return {
|
|
512
569
|
workspace: normalizedWorkspace,
|
|
513
570
|
name: normalizedName,
|
|
@@ -668,23 +725,23 @@ class ConfigManager {
|
|
|
668
725
|
return merged;
|
|
669
726
|
}
|
|
670
727
|
|
|
671
|
-
applyCodexProfileToLegacySettings(codexProfile) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
728
|
+
applyCodexProfileToLegacySettings(codexProfile, settings = this.settings) {
|
|
729
|
+
settings.codexApprovalMode = codexProfile.approvalMode;
|
|
730
|
+
settings.codexModel = codexProfile.model;
|
|
731
|
+
settings.codexReasoningEffort = codexProfile.reasoningEffort;
|
|
732
|
+
settings.codexServiceTier = codexProfile.serviceTier;
|
|
733
|
+
settings.codexModelPreset = codexProfile.modelPreset;
|
|
677
734
|
}
|
|
678
735
|
|
|
679
|
-
normalizeAgentLaunchSettings(rawSettings = {}) {
|
|
736
|
+
normalizeAgentLaunchSettings(rawSettings = {}, settings = this.settings) {
|
|
680
737
|
const changedProfiles = this.getChangedAgentLaunchProfiles(rawSettings);
|
|
681
|
-
const mergedProfiles = this.mergeAgentLaunchProfiles(
|
|
682
|
-
|
|
738
|
+
const mergedProfiles = this.mergeAgentLaunchProfiles(settings.agentLaunchProfiles, changedProfiles);
|
|
739
|
+
settings.agentLaunchProfiles = {
|
|
683
740
|
codex: this.normalizeCodexLaunchProfile(mergedProfiles.codex, changedProfiles.codex || {}),
|
|
684
741
|
claude: this.normalizeClaudeLaunchProfile(mergedProfiles.claude),
|
|
685
742
|
};
|
|
686
|
-
|
|
687
|
-
this.applyCodexProfileToLegacySettings(
|
|
743
|
+
settings.defaultLaunchAgent = this.normalizeDefaultLaunchAgent(settings.defaultLaunchAgent);
|
|
744
|
+
this.applyCodexProfileToLegacySettings(settings.agentLaunchProfiles.codex, settings);
|
|
688
745
|
}
|
|
689
746
|
|
|
690
747
|
getWorkspace() {
|
|
@@ -760,8 +817,10 @@ class ConfigManager {
|
|
|
760
817
|
}
|
|
761
818
|
|
|
762
819
|
getSettings() {
|
|
820
|
+
const publicSettings = { ...this.settings };
|
|
821
|
+
delete publicSettings.projectOperations;
|
|
763
822
|
return {
|
|
764
|
-
...
|
|
823
|
+
...publicSettings,
|
|
765
824
|
instanceName: this.getInstanceName(),
|
|
766
825
|
workspace: this.farmingDir,
|
|
767
826
|
mainPageSessionKeys: this.getMainPageSessionKeys(),
|
|
@@ -783,7 +842,6 @@ class ConfigManager {
|
|
|
783
842
|
}
|
|
784
843
|
if (
|
|
785
844
|
!canonicalWorkspace
|
|
786
|
-
|| canonicalWorkspace === path.parse(canonicalWorkspace).root
|
|
787
845
|
|| this.isInternalWorkspace(canonicalWorkspace)
|
|
788
846
|
) {
|
|
789
847
|
throw new Error('Project workspace is invalid or unavailable');
|
|
@@ -860,6 +918,64 @@ class ConfigManager {
|
|
|
860
918
|
}
|
|
861
919
|
}
|
|
862
920
|
|
|
921
|
+
getProjectOperation(requestId) {
|
|
922
|
+
const id = String(requestId || '').trim();
|
|
923
|
+
if (!PROJECT_OPERATION_ID_PATTERN.test(id)) return null;
|
|
924
|
+
const operation = this.settings.projectOperations?.[id];
|
|
925
|
+
return operation ? JSON.parse(JSON.stringify(operation)) : null;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
commitProjectOperation(operation, membership = {}) {
|
|
929
|
+
const normalized = this.normalizeProjectOperations({ [operation?.id]: operation });
|
|
930
|
+
const nextOperation = normalized[operation?.id];
|
|
931
|
+
if (!nextOperation) throw new Error('Project operation is invalid');
|
|
932
|
+
const existingOperation = this.settings.projectOperations?.[nextOperation.id];
|
|
933
|
+
const unresolvedCount = Object.values(this.settings.projectOperations || {})
|
|
934
|
+
.filter(candidate => ['pending', 'unknown', 'blocked'].includes(candidate.state)).length;
|
|
935
|
+
if (!existingOperation && nextOperation.state === 'pending' && unresolvedCount >= MAX_PROJECT_OPERATIONS) {
|
|
936
|
+
throw new Error('Too many unresolved Project operations require reconciliation');
|
|
937
|
+
}
|
|
938
|
+
const nextOperations = this.normalizeProjectOperations({
|
|
939
|
+
...this.settings.projectOperations,
|
|
940
|
+
[nextOperation.id]: nextOperation,
|
|
941
|
+
});
|
|
942
|
+
const nextSettings = {
|
|
943
|
+
...this.settings,
|
|
944
|
+
projectOperations: nextOperations,
|
|
945
|
+
};
|
|
946
|
+
if (membership.mountWorkspace) {
|
|
947
|
+
const mounted = this.normalizeProjectWorkspaces([
|
|
948
|
+
membership.mountWorkspace,
|
|
949
|
+
...(this.settings.projectWorkspaces || []),
|
|
950
|
+
]);
|
|
951
|
+
nextSettings.projectWorkspaces = mounted;
|
|
952
|
+
nextSettings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(
|
|
953
|
+
this.settings.pinnedProjectWorkspaces,
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
if (membership.removeWorkspace) {
|
|
957
|
+
const expanded = this.expandWorkspacePath(membership.removeWorkspace);
|
|
958
|
+
const resolved = expanded ? path.resolve(expanded) : '';
|
|
959
|
+
const candidates = new Set([expanded, resolved].filter(Boolean));
|
|
960
|
+
try {
|
|
961
|
+
candidates.add(fs.realpathSync(resolved));
|
|
962
|
+
} catch {
|
|
963
|
+
// A deleted worktree is removed by its last canonical path.
|
|
964
|
+
}
|
|
965
|
+
nextSettings.projectWorkspaces = (this.settings.projectWorkspaces || [])
|
|
966
|
+
.filter(workspace => !candidates.has(workspace));
|
|
967
|
+
nextSettings.pinnedProjectWorkspaces = (this.settings.pinnedProjectWorkspaces || [])
|
|
968
|
+
.filter(workspace => !candidates.has(workspace));
|
|
969
|
+
}
|
|
970
|
+
this.writeSettingsFile(nextSettings);
|
|
971
|
+
this.settings = nextSettings;
|
|
972
|
+
return {
|
|
973
|
+
operation: JSON.parse(JSON.stringify(nextOperation)),
|
|
974
|
+
projectWorkspaces: [...(nextSettings.projectWorkspaces || [])],
|
|
975
|
+
pinnedProjectWorkspaces: [...(nextSettings.pinnedProjectWorkspaces || [])],
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
|
|
863
979
|
getMainPageSessionKeys() {
|
|
864
980
|
return this.sessionStore ? this.sessionStore.getMainPageSessionKeys() : [];
|
|
865
981
|
}
|
|
@@ -904,19 +1020,8 @@ class ConfigManager {
|
|
|
904
1020
|
return this.runHistoryStore ? this.runHistoryStore.getEntries() : [];
|
|
905
1021
|
}
|
|
906
1022
|
|
|
907
|
-
writeSettingsFile() {
|
|
908
|
-
|
|
909
|
-
const tempFile = `${this.settingsFile}.${process.pid}.${Date.now()}.tmp`;
|
|
910
|
-
try {
|
|
911
|
-
fs.writeFileSync(tempFile, JSON.stringify(this.settings, null, 2));
|
|
912
|
-
fs.renameSync(tempFile, this.settingsFile);
|
|
913
|
-
} finally {
|
|
914
|
-
try {
|
|
915
|
-
fs.unlinkSync(tempFile);
|
|
916
|
-
} catch {
|
|
917
|
-
// A successful rename already removed the temporary path.
|
|
918
|
-
}
|
|
919
|
-
}
|
|
1023
|
+
writeSettingsFile(settings = this.settings) {
|
|
1024
|
+
this.writeJson(this.settingsFile, settings);
|
|
920
1025
|
}
|
|
921
1026
|
|
|
922
1027
|
appendTaskHistory(entry) {
|
|
@@ -930,6 +1035,7 @@ class ConfigManager {
|
|
|
930
1035
|
: undefined;
|
|
931
1036
|
const settingsPatch = { ...(newSettings || {}) };
|
|
932
1037
|
delete settingsPatch.mainPageSessionKeys;
|
|
1038
|
+
delete settingsPatch.projectOperations;
|
|
933
1039
|
const incomingTaskHistory = Object.prototype.hasOwnProperty.call(settingsPatch, 'taskHistory')
|
|
934
1040
|
? settingsPatch.taskHistory
|
|
935
1041
|
: undefined;
|
|
@@ -937,38 +1043,41 @@ class ConfigManager {
|
|
|
937
1043
|
const previousMainWorkspace = this.settings.lastMainWorkspace || this.farmingDir;
|
|
938
1044
|
const previousProfiles = this.settings.agentLaunchProfiles || {};
|
|
939
1045
|
const incomingProfiles = settingsPatch.agentLaunchProfiles || {};
|
|
940
|
-
|
|
1046
|
+
const nextSettings = {
|
|
941
1047
|
...this.settings,
|
|
942
1048
|
...settingsPatch,
|
|
943
1049
|
agentLaunchProfiles: this.mergeAgentLaunchProfiles(previousProfiles, incomingProfiles),
|
|
944
1050
|
workspace: this.farmingDir
|
|
945
1051
|
};
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
delete
|
|
957
|
-
delete
|
|
1052
|
+
nextSettings.lastMainWorkspace = this.normalizeMainWorkspace(nextSettings.lastMainWorkspace, previousMainWorkspace);
|
|
1053
|
+
nextSettings.workspaceHistory = this.normalizeWorkspaceHistory(nextSettings.workspaceHistory);
|
|
1054
|
+
nextSettings.projectWorkspaces = this.normalizeProjectWorkspaces(nextSettings.projectWorkspaces);
|
|
1055
|
+
nextSettings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(nextSettings.pinnedProjectWorkspaces);
|
|
1056
|
+
nextSettings.projectNames = this.normalizeProjectNames(nextSettings.projectNames);
|
|
1057
|
+
nextSettings.projectOperations = this.normalizeProjectOperations(nextSettings.projectOperations);
|
|
1058
|
+
nextSettings.instanceName = this.normalizeInstanceName(nextSettings.instanceName);
|
|
1059
|
+
nextSettings.agentHomes = this.normalizeAgentHomes(nextSettings.agentHomes);
|
|
1060
|
+
nextSettings.updateUrl = this.normalizeUpdateUrl(nextSettings.updateUrl);
|
|
1061
|
+
nextSettings.searchTimeoutMs = this.normalizeSearchTimeoutMs(nextSettings.searchTimeoutMs);
|
|
1062
|
+
delete nextSettings.codexRuntimeMode;
|
|
1063
|
+
delete nextSettings.mainPageSessionKeys;
|
|
1064
|
+
delete nextSettings.taskHistory;
|
|
958
1065
|
if (incomingMainPageSessionKeys !== undefined) {
|
|
959
1066
|
this.setMainPageSessionKeys(incomingMainPageSessionKeys);
|
|
960
1067
|
}
|
|
961
1068
|
if (incomingTaskHistory !== undefined && this.runHistoryStore) {
|
|
962
1069
|
this.runHistoryStore.setEntries(incomingTaskHistory);
|
|
963
1070
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
this.
|
|
970
|
-
this.
|
|
971
|
-
this.
|
|
1071
|
+
nextSettings.appearance = this.normalizeAppearance(nextSettings.appearance);
|
|
1072
|
+
nextSettings.language = this.normalizeLanguage(nextSettings.language);
|
|
1073
|
+
nextSettings.browserExtensionEnabled = nextSettings.browserExtensionEnabled === true;
|
|
1074
|
+
nextSettings.crtSkinEffectsEnabled = nextSettings.crtSkinEffectsEnabled !== false;
|
|
1075
|
+
nextSettings.crtDynamicHeatEnabled = nextSettings.crtDynamicHeatEnabled === true;
|
|
1076
|
+
nextSettings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(nextSettings.crtTerminalFontSize);
|
|
1077
|
+
this.normalizeAgentLaunchSettings(settingsPatch, nextSettings);
|
|
1078
|
+
this.pruneUnknownSettings(nextSettings);
|
|
1079
|
+
this.writeSettingsFile(nextSettings);
|
|
1080
|
+
this.settings = nextSettings;
|
|
972
1081
|
}
|
|
973
1082
|
}
|
|
974
1083
|
|
package/backend/control-api.js
CHANGED
|
@@ -419,9 +419,10 @@ function createControlRouter(agentManager, options = {}) {
|
|
|
419
419
|
|
|
420
420
|
router.delete('/agents/:agentId', async (req, res) => {
|
|
421
421
|
const agentId = req.params.agentId;
|
|
422
|
+
const recordHistory = req.query?.recordHistory !== '0';
|
|
422
423
|
let requested;
|
|
423
424
|
try {
|
|
424
|
-
requested = await agentManager.requestKillAgent(agentId);
|
|
425
|
+
requested = await agentManager.requestKillAgent(agentId, { recordHistory });
|
|
425
426
|
} catch (error) {
|
|
426
427
|
res.status(503).json({
|
|
427
428
|
error: error?.message || 'Agent lifecycle recovery is unavailable',
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const storageLayout = require('./storage-layout');
|
|
4
|
+
|
|
5
|
+
const sourceFile = path.join(__dirname, 'farming-agent-bootstrap.zh_cn.md');
|
|
6
|
+
|
|
7
|
+
function renderFarmingAgentBootstrap() {
|
|
8
|
+
return fs.readFileSync(sourceFile, 'utf8').trim();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function ensureFarmingAgentBootstrapFile(configDir) {
|
|
12
|
+
const target = storageLayout.farmingAgentBootstrapFile(configDir);
|
|
13
|
+
const content = `${renderFarmingAgentBootstrap()}\n`;
|
|
14
|
+
try {
|
|
15
|
+
if (fs.readFileSync(target, 'utf8') === content) return target;
|
|
16
|
+
} catch {
|
|
17
|
+
// Install the current Farming-owned prompt below.
|
|
18
|
+
}
|
|
19
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
20
|
+
const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
21
|
+
fs.writeFileSync(temporary, content, { encoding: 'utf8', mode: 0o600 });
|
|
22
|
+
fs.renameSync(temporary, target);
|
|
23
|
+
return target;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function appendOpenCodeBootstrap(env, bootstrapFile) {
|
|
27
|
+
const next = { ...env };
|
|
28
|
+
let config = {};
|
|
29
|
+
if (next.OPENCODE_CONFIG_CONTENT) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(next.OPENCODE_CONFIG_CONTENT);
|
|
32
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) config = parsed;
|
|
33
|
+
} catch {
|
|
34
|
+
return next;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const instructions = Array.isArray(config.instructions)
|
|
38
|
+
? config.instructions.filter(value => typeof value === 'string')
|
|
39
|
+
: [];
|
|
40
|
+
config.instructions = [...new Set([...instructions, bootstrapFile])];
|
|
41
|
+
next.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);
|
|
42
|
+
return next;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
appendOpenCodeBootstrap,
|
|
47
|
+
ensureFarmingAgentBootstrapFile,
|
|
48
|
+
renderFarmingAgentBootstrap,
|
|
49
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
你由 Farming 启动并托管。Farming 是一个供用户同时运行、观察和管理多个 AI 编程 Agent 的工作区,统一承载 Agent 对话、终端、项目文件,以及可由用户和 Agent 共同使用的扩展资源。
|
|
2
|
+
|
|
3
|
+
Farming 可能为当前会话提供系统浏览器、Agent 协作等能力。能力是否可用以 `farming capabilities` 的实时结果为准,不要自行假设。
|
|
4
|
+
|
|
5
|
+
当任务需要查看或操作网页时,你可以主动查询能力,并自行决定是否创建新的 Farming Browser 或连接已有 Browser。Farming Browser 会显示在用户界面中,用户和你操作的是同一个浏览器会话。只启用完成当前任务所需的能力。
|
|
@@ -22,8 +22,8 @@ const DEFAULT_SERVER_STOP_TIMEOUT_MS = 30_000;
|
|
|
22
22
|
const SERVER_STOP_POLL_MS = 100;
|
|
23
23
|
const SERVER_PROCESS_IDENTITY_FORMAT = 'ps-lstart-c-utc-v1';
|
|
24
24
|
const SERVER_COMMANDS = new Set(['start', 'serve', 'daemon', 'stop', 'status', 'logs', 'url', 'help']);
|
|
25
|
-
const CONTROL_COMMANDS = new Set(['skills', 'memory', 'report', 'list', 'spawn', 'output', 'send', 'kill']);
|
|
26
|
-
const SERVER_BACKED_CONTROL_COMMANDS = new Set(['list', 'spawn', 'output', 'send', 'kill']);
|
|
25
|
+
const CONTROL_COMMANDS = new Set(['skills', 'capabilities', 'memory', 'report', 'list', 'spawn', 'output', 'send', 'kill']);
|
|
26
|
+
const SERVER_BACKED_CONTROL_COMMANDS = new Set(['capabilities', 'list', 'spawn', 'output', 'send', 'kill']);
|
|
27
27
|
|
|
28
28
|
function defaultConfigDir(env = process.env) {
|
|
29
29
|
return storageLayout.farmingConfigDir(env);
|
|
@@ -1086,6 +1086,8 @@ function usage() {
|
|
|
1086
1086
|
|
|
1087
1087
|
Agent control commands are also available:
|
|
1088
1088
|
farming skills
|
|
1089
|
+
farming capabilities [--json]
|
|
1090
|
+
farming browser <capability|create|list|start|stop|snapshot|navigate|click|fill|type|press|scroll|screenshot> ...
|
|
1089
1091
|
farming list [--json] [--parent <agentId>]
|
|
1090
1092
|
farming spawn --workspace <repo> -- <command...>
|
|
1091
1093
|
farming output <agentId> [--tail <chars>]
|
|
@@ -1125,6 +1127,11 @@ async function run(argv = process.argv.slice(2)) {
|
|
|
1125
1127
|
return 0;
|
|
1126
1128
|
}
|
|
1127
1129
|
|
|
1130
|
+
if (argv[0] === 'browser') {
|
|
1131
|
+
const { run: runBrowserCli } = require('../extensions/browser/bin/farming-browser');
|
|
1132
|
+
return runBrowserCli(argv.slice(1));
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1128
1135
|
if (SERVER_BACKED_CONTROL_COMMANDS.has(argv[0])) {
|
|
1129
1136
|
return runServerBackedControlCli(argv);
|
|
1130
1137
|
}
|
package/backend/farming-cli.js
CHANGED
|
@@ -8,6 +8,7 @@ const storageLayout = require('./storage-layout');
|
|
|
8
8
|
function usage() {
|
|
9
9
|
return `Usage:
|
|
10
10
|
farming skills
|
|
11
|
+
farming capabilities [--json]
|
|
11
12
|
farming memory report [--period today|yesterday|week] [--since <time>] [--until <time>] [--home <path>] [--json]
|
|
12
13
|
farming list [--json] [--parent <agentId>]
|
|
13
14
|
farming spawn [--workspace <path>] [--task <text>] [--parent <agentId>] [--json] -- <command...>
|
|
@@ -20,6 +21,7 @@ Examples:
|
|
|
20
21
|
farming memory report --period today
|
|
21
22
|
farming memory report --period week --json
|
|
22
23
|
farming skills
|
|
24
|
+
farming capabilities
|
|
23
25
|
farming list --parent "$FARMING_AGENT_ID"
|
|
24
26
|
farming output agent-123 --tail 2000
|
|
25
27
|
farming send agent-123 "Please run the focused tests"`;
|
|
@@ -76,6 +78,13 @@ function parseArgs(argv) {
|
|
|
76
78
|
return { command };
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
if (command === 'capabilities') {
|
|
82
|
+
if (rest.some(arg => arg !== '--json')) {
|
|
83
|
+
throw new Error('capabilities accepts only --json');
|
|
84
|
+
}
|
|
85
|
+
return { command, options: { json: rest.includes('--json') } };
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
if (command === 'memory' || command === 'report') {
|
|
80
89
|
const subcommand = command === 'memory' ? rest.shift() : 'report';
|
|
81
90
|
if (subcommand !== 'report') {
|
|
@@ -293,6 +302,42 @@ function formatAgent(agent) {
|
|
|
293
302
|
return `${marker} ${agent.id} | ${agent.command} | ${agent.status} | ${agent.cwd}${parent}${task}`;
|
|
294
303
|
}
|
|
295
304
|
|
|
305
|
+
function farmingCapabilities(browser) {
|
|
306
|
+
const state = browser?.available === true
|
|
307
|
+
? 'available'
|
|
308
|
+
: (browser?.enabled === true ? 'unavailable' : 'disabled');
|
|
309
|
+
return {
|
|
310
|
+
runtime: 'farming',
|
|
311
|
+
agentId: process.env.FARMING_AGENT_ID || '',
|
|
312
|
+
projectWorkspace: process.env.FARMING_PROJECT_WORKSPACE || '',
|
|
313
|
+
capabilities: [{
|
|
314
|
+
id: 'browser',
|
|
315
|
+
state,
|
|
316
|
+
summary: state === 'available'
|
|
317
|
+
? 'An installed system Chromium Browser can be created or attached in Farming on demand.'
|
|
318
|
+
: (browser?.message || 'System Browser integration is unavailable in Farming.'),
|
|
319
|
+
commands: state === 'available'
|
|
320
|
+
? {
|
|
321
|
+
list: 'farming browser list',
|
|
322
|
+
create: 'farming browser create',
|
|
323
|
+
help: 'farming browser --help',
|
|
324
|
+
}
|
|
325
|
+
: {},
|
|
326
|
+
}],
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function formatCapabilities(report) {
|
|
331
|
+
const lines = ['Farming runtime capabilities:'];
|
|
332
|
+
for (const capability of report.capabilities) {
|
|
333
|
+
lines.push(`- ${capability.id}: ${capability.state} — ${capability.summary}`);
|
|
334
|
+
for (const [label, command] of Object.entries(capability.commands || {})) {
|
|
335
|
+
lines.push(` ${label}: ${command}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return lines.join('\n');
|
|
339
|
+
}
|
|
340
|
+
|
|
296
341
|
async function run(argv = process.argv.slice(2), io = process) {
|
|
297
342
|
const parsed = parseArgs(argv);
|
|
298
343
|
|
|
@@ -306,6 +351,14 @@ async function run(argv = process.argv.slice(2), io = process) {
|
|
|
306
351
|
return 0;
|
|
307
352
|
}
|
|
308
353
|
|
|
354
|
+
if (parsed.command === 'capabilities') {
|
|
355
|
+
const report = farmingCapabilities(await request('/api/browsers/capability'));
|
|
356
|
+
io.stdout.write(parsed.options.json
|
|
357
|
+
? `${JSON.stringify(report, null, 2)}\n`
|
|
358
|
+
: `${formatCapabilities(report)}\n`);
|
|
359
|
+
return 0;
|
|
360
|
+
}
|
|
361
|
+
|
|
309
362
|
if (parsed.command === 'memory-report') {
|
|
310
363
|
const report = buildMemoryReport({
|
|
311
364
|
period: parsed.options.period,
|
|
@@ -382,6 +435,8 @@ async function run(argv = process.argv.slice(2), io = process) {
|
|
|
382
435
|
|
|
383
436
|
module.exports = {
|
|
384
437
|
formatAgent,
|
|
438
|
+
farmingCapabilities,
|
|
439
|
+
formatCapabilities,
|
|
385
440
|
getToken,
|
|
386
441
|
httpRequest,
|
|
387
442
|
isAuthDisabled,
|